1 2/* 3 * Copyright (c) 2024 Huawei Device Co., Ltd. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <iostream> 18#include <fstream> 19#include <sstream> 20#include <unistd.h> 21#include <fcntl.h> 22#include <vector> 23 24using namespace std; 25 26constexpr uint64_t PFN_MASK = ((1ULL << 55) - 1); 27constexpr uint64_t PAGE_SIZE = 1024 * 4; 28constexpr int ARG_MINIMUM = 2; 29constexpr int IN_RAM_OFFSET = 63; 30constexpr int IN_SWAP_OFFSET = 54; 31constexpr int SHARED_OFFSET = 53; 32constexpr int EXCLUSIVE_OFFSET = 52; 33constexpr int SOFTDIRTY_OFFSET = 51; 34struct MapInfo { 35 uint64_t startAddr; // 起始地址 36 uint64_t endAddr; // 结束地址 37 char read; 38 char write; 39 char execute; 40 char shared; 41 uint64_t offset; // 文件偏移量 42 string dev; // 设备号 43 string inode; // inode 号 44 std::string pathname; // 文件路径 45}; 46 47struct PageInfo { 48 unsigned int inRam; 49 unsigned int inSwap; 50 unsigned int shared; 51 unsigned int exclusive; 52 unsigned int softdirty; 53 unsigned long pfn; 54 uint64_t address; 55}; 56 57namespace { 58void PrintUsage(const string& program) 59{ 60 cout << "Usage: " << program << " pid" <<endl; 61} 62 63int ParseMapsLine(const string& line, MapInfo& mapping) 64{ 65 std::istringstream iss(line); 66 std::string token; 67 uint64_t start, end; 68 69 // 读取起始地址和结束地址 70 if (!(iss >> hex >> start)) { 71 return -1; 72 } 73 iss.ignore(1); // 忽略 '-' 74 if (!(iss >> hex >> end)) { 75 return -1; 76 } 77 mapping.startAddr = start; 78 mapping.endAddr = end; 79 80 // 读取权限并转换为整数 81 iss >> mapping.read; 82 iss >> mapping.write; 83 iss >> mapping.execute; 84 iss >> mapping.shared; 85 // 读取偏移量 86 if (!(iss >> mapping.offset)) { 87 return -1; 88 } 89 // 读取设备号 90 if (!(iss >> mapping.dev)) { 91 return -1; 92 } 93 // 读取 inode 号 94 if (!(iss >> mapping.inode)) { 95 return -1; 96 } 97 // 读取文件路径 98 if (!getline(iss, mapping.pathname)) { 99 mapping.pathname = "[anno]"; 100 }; 101 return 0; 102} 103 104void ParsePagemap(uint64_t entry, PageInfo & pginfo) 105{ 106 pginfo.inRam = (entry >> IN_RAM_OFFSET) & 0x1; 107 pginfo.inSwap = (entry >> IN_SWAP_OFFSET) & 0x1; 108 pginfo.shared = (entry >> SHARED_OFFSET) & 0x1; 109 pginfo.exclusive = (entry >> EXCLUSIVE_OFFSET) & 0x1; 110 pginfo.softdirty = (entry >> SOFTDIRTY_OFFSET) & 0x1; 111 pginfo.pfn = entry & PFN_MASK; 112} 113 114void PrintPage(const MapInfo& mapping, const PageInfo& page) 115{ 116 cout << hex << page.address << '-' << hex << (page.address + PAGE_SIZE) << " "; 117 cout << mapping.read << mapping.write << mapping.execute << mapping.shared << " "; 118 if (page.inRam) { 119 cout << hex << page.pfn; 120 } else if (page.inSwap) { 121 cout << "[in swap]"; 122 } else { 123 cout << "[not present]"; 124 } 125 cout<< " " << mapping.pathname << endl; 126} 127 128bool IsValidPid(const string& pid_str) 129{ 130 if (pid_str.empty()) { 131 return -1; 132 } 133 bool ret = all_of(pid_str.begin(), pid_str.end(), [](char c) { 134 return isdigit(c); 135 }); 136 return ret; 137} 138} // namespace 139 140int main(int argc, char* argv[]) 141{ 142 if (argc != ARG_MINIMUM) { 143 PrintUsage(argv[0]); 144 return -1; 145 } 146 string pid_str = argv[1]; 147 if (!IsValidPid(pid_str)) { 148 PrintUsage(argv[0]); 149 return -1; 150 } 151 int pid = stoi(argv[1]); 152 string mapsPath = "/proc/" + to_string(pid) + "/maps"; 153 ifstream maps_file(mapsPath, ios::binary); 154 if (!maps_file) { 155 cerr << "Failed to open maps file" << endl; 156 return -1; 157 } 158 159 string pagemapPath = "/proc/" + to_string(pid) + "/pagemap"; 160 int pagemapFd = open(pagemapPath.c_str(), O_RDONLY); 161 if (pagemapFd == -1) { 162 perror("Error opening file"); 163 return -1; 164 } 165 cout << "Address Range\t" << "Permissions\t" << "PFN\t" << "Path" << endl; 166 string line; 167 while (getline(maps_file, line)) { 168 MapInfo mapping; 169 bool ret = ParseMapsLine(line, mapping); 170 if (ret != 0) { 171 close(pagemapFd); 172 return ret; 173 } 174 for (uint64_t tmpAddr = mapping.startAddr; tmpAddr < mapping.endAddr; tmpAddr += PAGE_SIZE) { 175 // 计算文件中要读取的偏移量 176 uint64_t offset = (tmpAddr / PAGE_SIZE) * sizeof(unsigned long long); 177 uint64_t entry; 178 if (pread(pagemapFd, &entry, sizeof(entry), offset) != sizeof(entry)) { 179 perror("pread"); 180 break; 181 } 182 PageInfo page; 183 ParsePagemap(entry, page); 184 page.address = tmpAddr; 185 PrintPage(mapping, page); 186 } 187 } 188 maps_file.close(); 189 close(pagemapFd); 190 return 0; 191}