1 | //===-- LinuxProcMapsTest.cpp ---------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "gmock/gmock.h" |
10 | #include "gtest/gtest.h" |
11 | |
12 | #include "Plugins/Process/Utility/LinuxProcMaps.h" |
13 | #include "lldb/Target/MemoryRegionInfo.h" |
14 | #include "lldb/Utility/Status.h" |
15 | #include <tuple> |
16 | |
17 | using namespace lldb_private; |
18 | |
19 | typedef std::tuple<const char *, MemoryRegionInfos, const char *> |
20 | LinuxProcMapsTestParams; |
21 | |
22 | // Wrapper for convenience because Range is usually begin, size |
23 | static MemoryRegionInfo::RangeType make_range(lldb::addr_t begin, |
24 | lldb::addr_t end) { |
25 | MemoryRegionInfo::RangeType range(begin, 0); |
26 | range.SetRangeEnd(end); |
27 | return range; |
28 | } |
29 | |
30 | class LinuxProcMapsTestFixture |
31 | : public ::testing::TestWithParam<LinuxProcMapsTestParams> { |
32 | protected: |
33 | Status error; |
34 | std::string err_str; |
35 | MemoryRegionInfos regions; |
36 | LinuxMapCallback callback; |
37 | |
38 | void SetUp() override { |
39 | callback = [this](llvm::Expected<MemoryRegionInfo> Info) { |
40 | if (Info) { |
41 | err_str.clear(); |
42 | regions.push_back(x: *Info); |
43 | return true; |
44 | } |
45 | |
46 | err_str = toString(E: Info.takeError()); |
47 | return false; |
48 | }; |
49 | } |
50 | |
51 | void check_regions(LinuxProcMapsTestParams params) { |
52 | EXPECT_THAT(std::get<1>(params), testing::ContainerEq(regions)); |
53 | ASSERT_EQ(std::get<2>(params), err_str); |
54 | } |
55 | }; |
56 | |
57 | TEST_P(LinuxProcMapsTestFixture, ParseMapRegions) { |
58 | auto params = GetParam(); |
59 | ParseLinuxMapRegions(linux_map: std::get<0>(t&: params), callback); |
60 | check_regions(params); |
61 | } |
62 | |
63 | // Note: ConstString("") != ConstString(nullptr) |
64 | // When a region has no name, it will have the latter in the MemoryRegionInfo |
65 | INSTANTIATE_TEST_SUITE_P( |
66 | ProcMapTests, LinuxProcMapsTestFixture, |
67 | ::testing::Values( |
68 | // Nothing in nothing out |
69 | std::make_tuple("" , MemoryRegionInfos{}, "" ), |
70 | // Various formatting error conditions |
71 | std::make_tuple("55a4512f7000/55a451b68000 rw-p 00000000 00:00 0" , |
72 | MemoryRegionInfos{}, |
73 | "malformed /proc/{pid}/maps entry, missing dash " |
74 | "between address range" ), |
75 | std::make_tuple("0-0 rw" , MemoryRegionInfos{}, |
76 | "malformed /proc/{pid}/maps entry, missing some " |
77 | "portion of permissions" ), |
78 | std::make_tuple("0-0 z--p 00000000 00:00 0" , MemoryRegionInfos{}, |
79 | "unexpected /proc/{pid}/maps read permission char" ), |
80 | std::make_tuple("0-0 rz-p 00000000 00:00 0" , MemoryRegionInfos{}, |
81 | "unexpected /proc/{pid}/maps write permission char" ), |
82 | std::make_tuple("0-0 rwzp 00000000 00:00 0" , MemoryRegionInfos{}, |
83 | "unexpected /proc/{pid}/maps exec permission char" ), |
84 | // Stops at first parsing error |
85 | std::make_tuple( |
86 | "0-1 rw-p 00000000 00:00 0 [abc]\n" |
87 | "0-0 rwzp 00000000 00:00 0\n" |
88 | "2-3 r-xp 00000000 00:00 0 [def]\n" , |
89 | MemoryRegionInfos{ |
90 | MemoryRegionInfo( |
91 | make_range(0, 1), MemoryRegionInfo::eYes, |
92 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
93 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
94 | ConstString("[abc]" ), MemoryRegionInfo::eDontKnow, 0, |
95 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, |
96 | MemoryRegionInfo::eDontKnow), |
97 | }, |
98 | "unexpected /proc/{pid}/maps exec permission char" ), |
99 | // Single entry |
100 | std::make_tuple( |
101 | "55a4512f7000-55a451b68000 rw-p 00000000 00:00 0 [heap]" , |
102 | MemoryRegionInfos{ |
103 | MemoryRegionInfo( |
104 | make_range(0x55a4512f7000, 0x55a451b68000), |
105 | MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, |
106 | MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, |
107 | MemoryRegionInfo::eYes, ConstString("[heap]" ), |
108 | MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, |
109 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), |
110 | }, |
111 | "" ), |
112 | // Multiple entries |
113 | std::make_tuple( |
114 | "7fc090021000-7fc094000000 ---p 00000000 00:00 0\n" |
115 | "7fc094000000-7fc094a00000 ---s 00000000 00:00 0\n" |
116 | "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 " |
117 | "[vsyscall]" , |
118 | MemoryRegionInfos{ |
119 | MemoryRegionInfo( |
120 | make_range(0x7fc090021000, 0x7fc094000000), |
121 | MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, |
122 | MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, |
123 | MemoryRegionInfo::eYes, ConstString(nullptr), |
124 | MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, |
125 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), |
126 | MemoryRegionInfo( |
127 | make_range(0x7fc094000000, 0x7fc094a00000), |
128 | MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, |
129 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
130 | MemoryRegionInfo::eYes, ConstString(nullptr), |
131 | MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, |
132 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), |
133 | MemoryRegionInfo( |
134 | make_range(0xffffffffff600000, 0xffffffffff601000), |
135 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
136 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
137 | MemoryRegionInfo::eYes, ConstString("[vsyscall]" ), |
138 | MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, |
139 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), |
140 | }, |
141 | "" ))); |
142 | |
143 | class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {}; |
144 | |
145 | INSTANTIATE_TEST_SUITE_P( |
146 | ProcSMapTests, LinuxProcSMapsTestFixture, |
147 | ::testing::Values( |
148 | // Nothing in nothing out |
149 | std::make_tuple("" , MemoryRegionInfos{}, "" ), |
150 | // Uses the same parsing for first line, so same errors but referring to |
151 | // smaps |
152 | std::make_tuple("0/0 rw-p 00000000 00:00 0" , MemoryRegionInfos{}, |
153 | "malformed /proc/{pid}/smaps entry, missing dash " |
154 | "between address range" ), |
155 | // Stop parsing at first error |
156 | std::make_tuple( |
157 | "1111-2222 rw-p 00000000 00:00 0 [foo]\n" |
158 | "0/0 rw-p 00000000 00:00 0" , |
159 | MemoryRegionInfos{ |
160 | MemoryRegionInfo( |
161 | make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, |
162 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
163 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
164 | ConstString("[foo]" ), MemoryRegionInfo::eDontKnow, 0, |
165 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, |
166 | MemoryRegionInfo::eDontKnow), |
167 | }, |
168 | "malformed /proc/{pid}/smaps entry, missing dash between address " |
169 | "range" ), |
170 | // Property line without a region is an error |
171 | std::make_tuple("Referenced: 2188 kB\n" |
172 | "1111-2222 rw-p 00000000 00:00 0 [foo]\n" |
173 | "3333-4444 rw-p 00000000 00:00 0 [bar]\n" , |
174 | MemoryRegionInfos{}, |
175 | "Found a property line without a corresponding mapping " |
176 | "in /proc/{pid}/smaps" ), |
177 | // Single region parses, has no flags |
178 | std::make_tuple( |
179 | "1111-2222 rw-p 00000000 00:00 0 [foo]" , |
180 | MemoryRegionInfos{ |
181 | MemoryRegionInfo( |
182 | make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, |
183 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
184 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
185 | ConstString("[foo]" ), MemoryRegionInfo::eDontKnow, 0, |
186 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, |
187 | MemoryRegionInfo::eDontKnow), |
188 | }, |
189 | "" ), |
190 | // Single shared region parses, has no flags |
191 | std::make_tuple( |
192 | "1111-2222 rw-s 00000000 00:00 0 [foo]" , |
193 | MemoryRegionInfos{ |
194 | MemoryRegionInfo( |
195 | make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, |
196 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
197 | MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, |
198 | ConstString("[foo]" ), MemoryRegionInfo::eDontKnow, 0, |
199 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, |
200 | MemoryRegionInfo::eDontKnow), |
201 | }, |
202 | "" ), |
203 | // Single region with flags, other lines ignored |
204 | std::make_tuple( |
205 | "1111-2222 rw-p 00000000 00:00 0 [foo]\n" |
206 | "Referenced: 2188 kB\n" |
207 | "AnonHugePages: 0 kB\n" |
208 | "VmFlags: mt" , |
209 | MemoryRegionInfos{ |
210 | MemoryRegionInfo( |
211 | make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, |
212 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
213 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
214 | ConstString("[foo]" ), MemoryRegionInfo::eDontKnow, 0, |
215 | MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, |
216 | MemoryRegionInfo::eNo), |
217 | }, |
218 | "" ), |
219 | // Whitespace ignored |
220 | std::make_tuple( |
221 | "0-0 rw-p 00000000 00:00 0\n" |
222 | "VmFlags: mt " , |
223 | MemoryRegionInfos{ |
224 | MemoryRegionInfo( |
225 | make_range(0, 0), MemoryRegionInfo::eYes, |
226 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
227 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
228 | ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, |
229 | MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, |
230 | MemoryRegionInfo::eNo), |
231 | }, |
232 | "" ), |
233 | // VmFlags line means it has flag info, but nothing is set |
234 | std::make_tuple( |
235 | "0-0 rw-p 00000000 00:00 0\n" |
236 | "VmFlags: " , |
237 | MemoryRegionInfos{ |
238 | MemoryRegionInfo( |
239 | make_range(0, 0), MemoryRegionInfo::eYes, |
240 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
241 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
242 | ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, |
243 | MemoryRegionInfo::eNo, MemoryRegionInfo::eDontKnow, |
244 | MemoryRegionInfo::eNo), |
245 | }, |
246 | "" ), |
247 | // Handle some pages not having a flags line |
248 | std::make_tuple( |
249 | "1111-2222 rw-p 00000000 00:00 0 [foo]\n" |
250 | "Referenced: 2188 kB\n" |
251 | "AnonHugePages: 0 kB\n" |
252 | "3333-4444 r-xp 00000000 00:00 0 [bar]\n" |
253 | "VmFlags: mt" , |
254 | MemoryRegionInfos{ |
255 | MemoryRegionInfo( |
256 | make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, |
257 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
258 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
259 | ConstString("[foo]" ), MemoryRegionInfo::eDontKnow, 0, |
260 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, |
261 | MemoryRegionInfo::eDontKnow), |
262 | MemoryRegionInfo( |
263 | make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, |
264 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
265 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
266 | ConstString("[bar]" ), MemoryRegionInfo::eDontKnow, 0, |
267 | MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, |
268 | MemoryRegionInfo::eNo), |
269 | }, |
270 | "" ), |
271 | // Handle no pages having a flags line (older kernels) |
272 | std::make_tuple( |
273 | "1111-2222 rw-p 00000000 00:00 0\n" |
274 | "Referenced: 2188 kB\n" |
275 | "AnonHugePages: 0 kB\n" |
276 | "3333-4444 r-xp 00000000 00:00 0\n" |
277 | "KernelPageSize: 4 kB\n" |
278 | "MMUPageSize: 4 kB\n" , |
279 | MemoryRegionInfos{ |
280 | MemoryRegionInfo( |
281 | make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, |
282 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
283 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
284 | ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, |
285 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, |
286 | MemoryRegionInfo::eDontKnow), |
287 | MemoryRegionInfo( |
288 | make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, |
289 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
290 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
291 | ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, |
292 | MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, |
293 | MemoryRegionInfo::eDontKnow), |
294 | }, |
295 | "" ), |
296 | // We must look for exact flag strings, ignoring substrings of longer |
297 | // flag names. |
298 | std::make_tuple( |
299 | "0-0 rw-p 00000000 00:00 0\n" |
300 | "VmFlags: amt mtb amtb" , |
301 | MemoryRegionInfos{ |
302 | MemoryRegionInfo( |
303 | make_range(0, 0), MemoryRegionInfo::eYes, |
304 | MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, |
305 | MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, |
306 | ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, |
307 | MemoryRegionInfo::eNo, MemoryRegionInfo::eDontKnow, |
308 | MemoryRegionInfo::eNo), |
309 | }, |
310 | "" ))); |
311 | |
312 | TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) { |
313 | auto params = GetParam(); |
314 | ParseLinuxSMapRegions(linux_smap: std::get<0>(t&: params), callback); |
315 | check_regions(params); |
316 | } |
317 | |