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
24 using namespace std;
25
26 constexpr uint64_t PFN_MASK = ((1ULL << 55) - 1);
27 constexpr uint64_t PAGE_SIZE = 1024 * 4;
28 constexpr int ARG_MINIMUM = 2;
29 constexpr int IN_RAM_OFFSET = 63;
30 constexpr int IN_SWAP_OFFSET = 54;
31 constexpr int SHARED_OFFSET = 53;
32 constexpr int EXCLUSIVE_OFFSET = 52;
33 constexpr int SOFTDIRTY_OFFSET = 51;
34 struct 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
47 struct 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
57 namespace {
PrintUsage(const string & program)58 void PrintUsage(const string& program)
59 {
60 cout << "Usage: " << program << " pid" <<endl;
61 }
62
ParseMapsLine(const string & line,MapInfo & mapping)63 int ParseMapsLine(const string& line, MapInfo& mapping)
64 {
65 std::istringstream iss(line);
66 uint64_t start, end;
67
68 // 读取起始地址和结束地址
69 if (!(iss >> hex >> start)) {
70 return -1;
71 }
72 iss.ignore(1); // 忽略 '-'
73 if (!(iss >> hex >> end)) {
74 return -1;
75 }
76 mapping.startAddr = start;
77 mapping.endAddr = end;
78
79 // 读取权限并转换为整数
80 iss >> mapping.read;
81 iss >> mapping.write;
82 iss >> mapping.execute;
83 iss >> mapping.shared;
84 // 读取偏移量
85 if (!(iss >> mapping.offset)) {
86 return -1;
87 }
88 // 读取设备号
89 if (!(iss >> mapping.dev)) {
90 return -1;
91 }
92 // 读取 inode 号
93 if (!(iss >> mapping.inode)) {
94 return -1;
95 }
96 // 读取文件路径
97 if (!getline(iss, mapping.pathname)) {
98 mapping.pathname = "[anno]";
99 };
100 return 0;
101 }
102
ParsePagemap(uint64_t entry,PageInfo & pginfo)103 void ParsePagemap(uint64_t entry, PageInfo & pginfo)
104 {
105 pginfo.inRam = (entry >> IN_RAM_OFFSET) & 0x1;
106 pginfo.inSwap = (entry >> IN_SWAP_OFFSET) & 0x1;
107 pginfo.shared = (entry >> SHARED_OFFSET) & 0x1;
108 pginfo.exclusive = (entry >> EXCLUSIVE_OFFSET) & 0x1;
109 pginfo.softdirty = (entry >> SOFTDIRTY_OFFSET) & 0x1;
110 pginfo.pfn = entry & PFN_MASK;
111 }
112
PrintPage(const MapInfo & mapping,const PageInfo & page)113 void PrintPage(const MapInfo& mapping, const PageInfo& page)
114 {
115 cout << hex << page.address << '-' << hex << (page.address + PAGE_SIZE) << " ";
116 cout << mapping.read << mapping.write << mapping.execute << mapping.shared << " ";
117 if (page.inRam) {
118 cout << hex << page.pfn;
119 } else if (page.inSwap) {
120 cout << "[in swap]";
121 } else {
122 cout << "[not present]";
123 }
124 cout<< " " << mapping.pathname << endl;
125 }
126
IsValidPid(const string & pid_str)127 bool IsValidPid(const string& pid_str)
128 {
129 if (pid_str.empty()) {
130 return false;
131 }
132 bool ret = all_of(pid_str.begin(), pid_str.end(), [](char c) {
133 return isdigit(c);
134 });
135 return ret;
136 }
137 } // namespace
138
main(int argc,char * argv[])139 int main(int argc, char* argv[])
140 {
141 if (argc != ARG_MINIMUM) {
142 PrintUsage(argv[0]);
143 return -1;
144 }
145 string pid_str = argv[1];
146 if (!IsValidPid(pid_str)) {
147 PrintUsage(argv[0]);
148 return -1;
149 }
150 int pid = stoi(argv[1]);
151 string mapsPath = "/proc/" + to_string(pid) + "/maps";
152 ifstream maps_file(mapsPath, ios::binary);
153 if (!maps_file) {
154 cerr << "Failed to open maps file" << endl;
155 return -1;
156 }
157
158 string pagemapPath = "/proc/" + to_string(pid) + "/pagemap";
159 int pagemapFd = open(pagemapPath.c_str(), O_RDONLY);
160 if (pagemapFd == -1) {
161 perror("Error opening file");
162 return -1;
163 }
164 cout << "Address Range\t" << "Permissions\t" << "PFN\t" << "Path" << endl;
165 string line;
166 while (getline(maps_file, line)) {
167 MapInfo mapping;
168 bool ret = ParseMapsLine(line, mapping);
169 if (ret != 0) {
170 close(pagemapFd);
171 return ret;
172 }
173 for (uint64_t tmpAddr = mapping.startAddr; tmpAddr < mapping.endAddr; tmpAddr += PAGE_SIZE) {
174 // 计算文件中要读取的偏移量
175 uint64_t offset = (tmpAddr / PAGE_SIZE) * sizeof(unsigned long long);
176 uint64_t entry;
177 if (pread(pagemapFd, &entry, sizeof(entry), offset) != sizeof(entry)) {
178 perror("pread");
179 break;
180 }
181 PageInfo page;
182 ParsePagemap(entry, page);
183 page.address = tmpAddr;
184 PrintPage(mapping, page);
185 }
186 }
187 maps_file.close();
188 close(pagemapFd);
189 return 0;
190 }