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 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
ParsePagemap(uint64_t entry, PageInfo & pginfo)104 void 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
PrintPage(const MapInfo& mapping, const PageInfo& page)114 void 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
IsValidPid(const string& pid_str)128 bool 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
main(int argc, char* argv[])140 int 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 }