• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }