106f6ba60Sopenharmony_ci
206f6ba60Sopenharmony_ci/*
306f6ba60Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
406f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
506f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License.
606f6ba60Sopenharmony_ci * You may obtain a copy of the License at
706f6ba60Sopenharmony_ci *
806f6ba60Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
906f6ba60Sopenharmony_ci *
1006f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1106f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1206f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1306f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and
1406f6ba60Sopenharmony_ci * limitations under the License.
1506f6ba60Sopenharmony_ci */
1606f6ba60Sopenharmony_ci
1706f6ba60Sopenharmony_ci#include <iostream>
1806f6ba60Sopenharmony_ci#include <fstream>
1906f6ba60Sopenharmony_ci#include <sstream>
2006f6ba60Sopenharmony_ci#include <unistd.h>
2106f6ba60Sopenharmony_ci#include <fcntl.h>
2206f6ba60Sopenharmony_ci#include <vector>
2306f6ba60Sopenharmony_ci
2406f6ba60Sopenharmony_ciusing namespace std;
2506f6ba60Sopenharmony_ci
2606f6ba60Sopenharmony_ciconstexpr uint64_t PFN_MASK = ((1ULL << 55) - 1);
2706f6ba60Sopenharmony_ciconstexpr uint64_t PAGE_SIZE = 1024 * 4;
2806f6ba60Sopenharmony_ciconstexpr int ARG_MINIMUM = 2;
2906f6ba60Sopenharmony_ciconstexpr int IN_RAM_OFFSET = 63;
3006f6ba60Sopenharmony_ciconstexpr int IN_SWAP_OFFSET = 54;
3106f6ba60Sopenharmony_ciconstexpr int SHARED_OFFSET = 53;
3206f6ba60Sopenharmony_ciconstexpr int EXCLUSIVE_OFFSET = 52;
3306f6ba60Sopenharmony_ciconstexpr int SOFTDIRTY_OFFSET = 51;
3406f6ba60Sopenharmony_cistruct MapInfo {
3506f6ba60Sopenharmony_ci    uint64_t startAddr; // 起始地址
3606f6ba60Sopenharmony_ci    uint64_t endAddr;   // 结束地址
3706f6ba60Sopenharmony_ci    char read;
3806f6ba60Sopenharmony_ci    char write;
3906f6ba60Sopenharmony_ci    char execute;
4006f6ba60Sopenharmony_ci    char shared;
4106f6ba60Sopenharmony_ci    uint64_t offset;    // 文件偏移量
4206f6ba60Sopenharmony_ci    string dev;       // 设备号
4306f6ba60Sopenharmony_ci    string inode;     // inode 号
4406f6ba60Sopenharmony_ci    std::string pathname;  // 文件路径
4506f6ba60Sopenharmony_ci};
4606f6ba60Sopenharmony_ci
4706f6ba60Sopenharmony_cistruct PageInfo {
4806f6ba60Sopenharmony_ci    unsigned int inRam;
4906f6ba60Sopenharmony_ci    unsigned int inSwap;
5006f6ba60Sopenharmony_ci    unsigned int shared;
5106f6ba60Sopenharmony_ci    unsigned int exclusive;
5206f6ba60Sopenharmony_ci    unsigned int softdirty;
5306f6ba60Sopenharmony_ci    unsigned long pfn;
5406f6ba60Sopenharmony_ci    uint64_t address;
5506f6ba60Sopenharmony_ci};
5606f6ba60Sopenharmony_ci
5706f6ba60Sopenharmony_cinamespace {
5806f6ba60Sopenharmony_civoid PrintUsage(const string& program)
5906f6ba60Sopenharmony_ci{
6006f6ba60Sopenharmony_ci    cout << "Usage: " << program << " pid" <<endl;
6106f6ba60Sopenharmony_ci}
6206f6ba60Sopenharmony_ci
6306f6ba60Sopenharmony_ciint ParseMapsLine(const string& line, MapInfo& mapping)
6406f6ba60Sopenharmony_ci{
6506f6ba60Sopenharmony_ci    std::istringstream iss(line);
6606f6ba60Sopenharmony_ci    std::string token;
6706f6ba60Sopenharmony_ci    uint64_t start, end;
6806f6ba60Sopenharmony_ci
6906f6ba60Sopenharmony_ci    // 读取起始地址和结束地址
7006f6ba60Sopenharmony_ci    if (!(iss >> hex >> start)) {
7106f6ba60Sopenharmony_ci        return -1;
7206f6ba60Sopenharmony_ci    }
7306f6ba60Sopenharmony_ci    iss.ignore(1); // 忽略 '-'
7406f6ba60Sopenharmony_ci    if (!(iss >> hex >> end))  {
7506f6ba60Sopenharmony_ci        return -1;
7606f6ba60Sopenharmony_ci    }
7706f6ba60Sopenharmony_ci    mapping.startAddr = start;
7806f6ba60Sopenharmony_ci    mapping.endAddr = end;
7906f6ba60Sopenharmony_ci
8006f6ba60Sopenharmony_ci    // 读取权限并转换为整数
8106f6ba60Sopenharmony_ci    iss >> mapping.read;
8206f6ba60Sopenharmony_ci    iss >> mapping.write;
8306f6ba60Sopenharmony_ci    iss >> mapping.execute;
8406f6ba60Sopenharmony_ci    iss >> mapping.shared;
8506f6ba60Sopenharmony_ci    // 读取偏移量
8606f6ba60Sopenharmony_ci    if (!(iss >> mapping.offset))  {
8706f6ba60Sopenharmony_ci        return -1;
8806f6ba60Sopenharmony_ci    }
8906f6ba60Sopenharmony_ci    // 读取设备号
9006f6ba60Sopenharmony_ci    if (!(iss >> mapping.dev))  {
9106f6ba60Sopenharmony_ci        return -1;
9206f6ba60Sopenharmony_ci    }
9306f6ba60Sopenharmony_ci    // 读取 inode 号
9406f6ba60Sopenharmony_ci    if (!(iss >> mapping.inode))  {
9506f6ba60Sopenharmony_ci        return -1;
9606f6ba60Sopenharmony_ci    }
9706f6ba60Sopenharmony_ci    // 读取文件路径
9806f6ba60Sopenharmony_ci    if (!getline(iss, mapping.pathname)) {
9906f6ba60Sopenharmony_ci        mapping.pathname = "[anno]";
10006f6ba60Sopenharmony_ci    };
10106f6ba60Sopenharmony_ci    return 0;
10206f6ba60Sopenharmony_ci}
10306f6ba60Sopenharmony_ci
10406f6ba60Sopenharmony_civoid ParsePagemap(uint64_t entry, PageInfo & pginfo)
10506f6ba60Sopenharmony_ci{
10606f6ba60Sopenharmony_ci    pginfo.inRam    = (entry >> IN_RAM_OFFSET) & 0x1;
10706f6ba60Sopenharmony_ci    pginfo.inSwap   = (entry >> IN_SWAP_OFFSET) & 0x1;
10806f6ba60Sopenharmony_ci    pginfo.shared    = (entry >> SHARED_OFFSET) & 0x1;
10906f6ba60Sopenharmony_ci    pginfo.exclusive = (entry >> EXCLUSIVE_OFFSET) & 0x1;
11006f6ba60Sopenharmony_ci    pginfo.softdirty = (entry >> SOFTDIRTY_OFFSET) & 0x1;
11106f6ba60Sopenharmony_ci    pginfo.pfn       = entry & PFN_MASK;
11206f6ba60Sopenharmony_ci}
11306f6ba60Sopenharmony_ci
11406f6ba60Sopenharmony_civoid PrintPage(const MapInfo& mapping, const PageInfo& page)
11506f6ba60Sopenharmony_ci{
11606f6ba60Sopenharmony_ci    cout << hex << page.address << '-' << hex << (page.address + PAGE_SIZE) << " ";
11706f6ba60Sopenharmony_ci    cout << mapping.read << mapping.write << mapping.execute << mapping.shared << " ";
11806f6ba60Sopenharmony_ci    if (page.inRam) {
11906f6ba60Sopenharmony_ci        cout << hex << page.pfn;
12006f6ba60Sopenharmony_ci    } else if (page.inSwap) {
12106f6ba60Sopenharmony_ci        cout << "[in swap]";
12206f6ba60Sopenharmony_ci    } else {
12306f6ba60Sopenharmony_ci        cout << "[not present]";
12406f6ba60Sopenharmony_ci    }
12506f6ba60Sopenharmony_ci    cout<< " " << mapping.pathname << endl;
12606f6ba60Sopenharmony_ci}
12706f6ba60Sopenharmony_ci
12806f6ba60Sopenharmony_cibool IsValidPid(const string& pid_str)
12906f6ba60Sopenharmony_ci{
13006f6ba60Sopenharmony_ci    if (pid_str.empty()) {
13106f6ba60Sopenharmony_ci        return -1;
13206f6ba60Sopenharmony_ci    }
13306f6ba60Sopenharmony_ci    bool ret = all_of(pid_str.begin(), pid_str.end(), [](char c) {
13406f6ba60Sopenharmony_ci        return isdigit(c);
13506f6ba60Sopenharmony_ci    });
13606f6ba60Sopenharmony_ci    return ret;
13706f6ba60Sopenharmony_ci}
13806f6ba60Sopenharmony_ci} // namespace
13906f6ba60Sopenharmony_ci
14006f6ba60Sopenharmony_ciint main(int argc, char* argv[])
14106f6ba60Sopenharmony_ci{
14206f6ba60Sopenharmony_ci    if (argc != ARG_MINIMUM) {
14306f6ba60Sopenharmony_ci        PrintUsage(argv[0]);
14406f6ba60Sopenharmony_ci        return -1;
14506f6ba60Sopenharmony_ci    }
14606f6ba60Sopenharmony_ci    string pid_str = argv[1];
14706f6ba60Sopenharmony_ci    if (!IsValidPid(pid_str)) {
14806f6ba60Sopenharmony_ci        PrintUsage(argv[0]);
14906f6ba60Sopenharmony_ci        return -1;
15006f6ba60Sopenharmony_ci    }
15106f6ba60Sopenharmony_ci    int pid = stoi(argv[1]);
15206f6ba60Sopenharmony_ci    string mapsPath = "/proc/" + to_string(pid) + "/maps";
15306f6ba60Sopenharmony_ci    ifstream maps_file(mapsPath, ios::binary);
15406f6ba60Sopenharmony_ci    if (!maps_file) {
15506f6ba60Sopenharmony_ci        cerr << "Failed to open maps file" << endl;
15606f6ba60Sopenharmony_ci        return -1;
15706f6ba60Sopenharmony_ci    }
15806f6ba60Sopenharmony_ci
15906f6ba60Sopenharmony_ci    string pagemapPath = "/proc/" + to_string(pid) + "/pagemap";
16006f6ba60Sopenharmony_ci    int pagemapFd = open(pagemapPath.c_str(), O_RDONLY);
16106f6ba60Sopenharmony_ci    if (pagemapFd == -1) {
16206f6ba60Sopenharmony_ci        perror("Error opening file");
16306f6ba60Sopenharmony_ci        return -1;
16406f6ba60Sopenharmony_ci    }
16506f6ba60Sopenharmony_ci    cout << "Address Range\t" << "Permissions\t" << "PFN\t" << "Path" << endl;
16606f6ba60Sopenharmony_ci    string line;
16706f6ba60Sopenharmony_ci    while (getline(maps_file, line)) {
16806f6ba60Sopenharmony_ci        MapInfo mapping;
16906f6ba60Sopenharmony_ci        bool ret = ParseMapsLine(line, mapping);
17006f6ba60Sopenharmony_ci        if (ret != 0) {
17106f6ba60Sopenharmony_ci            close(pagemapFd);
17206f6ba60Sopenharmony_ci            return ret;
17306f6ba60Sopenharmony_ci        }
17406f6ba60Sopenharmony_ci        for (uint64_t tmpAddr = mapping.startAddr; tmpAddr < mapping.endAddr; tmpAddr += PAGE_SIZE) {
17506f6ba60Sopenharmony_ci            // 计算文件中要读取的偏移量
17606f6ba60Sopenharmony_ci            uint64_t offset = (tmpAddr / PAGE_SIZE) * sizeof(unsigned long long);
17706f6ba60Sopenharmony_ci            uint64_t entry;
17806f6ba60Sopenharmony_ci            if (pread(pagemapFd, &entry, sizeof(entry), offset) != sizeof(entry)) {
17906f6ba60Sopenharmony_ci                perror("pread");
18006f6ba60Sopenharmony_ci                break;
18106f6ba60Sopenharmony_ci            }
18206f6ba60Sopenharmony_ci            PageInfo page;
18306f6ba60Sopenharmony_ci            ParsePagemap(entry, page);
18406f6ba60Sopenharmony_ci            page.address = tmpAddr;
18506f6ba60Sopenharmony_ci            PrintPage(mapping, page);
18606f6ba60Sopenharmony_ci        }
18706f6ba60Sopenharmony_ci    }
18806f6ba60Sopenharmony_ci    maps_file.close();
18906f6ba60Sopenharmony_ci    close(pagemapFd);
19006f6ba60Sopenharmony_ci    return 0;
19106f6ba60Sopenharmony_ci}