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
17using namespace lldb_private;
18
19typedef std::tuple<const char *, MemoryRegionInfos, const char *>
20 LinuxProcMapsTestParams;
21
22// Wrapper for convenience because Range is usually begin, size
23static 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
30class LinuxProcMapsTestFixture
31 : public ::testing::TestWithParam<LinuxProcMapsTestParams> {
32protected:
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
57TEST_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
65INSTANTIATE_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(make_range(0, 1), MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
91 MemoryRegionInfo::eNo,
92 MemoryRegionInfo::eYes, ConstString("[abc]"),
93 MemoryRegionInfo::eDontKnow, 0,
94 MemoryRegionInfo::eDontKnow,
95 MemoryRegionInfo::eDontKnow),
96 },
97 "unexpected /proc/{pid}/maps exec permission char"),
98 // Single entry
99 std::make_tuple(
100 "55a4512f7000-55a451b68000 rw-p 00000000 00:00 0 [heap]",
101 MemoryRegionInfos{
102 MemoryRegionInfo(
103 make_range(0x55a4512f7000, 0x55a451b68000),
104 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
105 MemoryRegionInfo::eNo,
106 MemoryRegionInfo::eYes,
107 ConstString("[heap]"), MemoryRegionInfo::eDontKnow, 0,
108 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
109 },
110 ""),
111 // Multiple entries
112 std::make_tuple(
113 "7fc090021000-7fc094000000 ---p 00000000 00:00 0\n"
114 "7fc094000000-7fc094a00000 ---s 00000000 00:00 0\n"
115 "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
116 "[vsyscall]",
117 MemoryRegionInfos{
118 MemoryRegionInfo(
119 make_range(0x7fc090021000, 0x7fc094000000),
120 MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, MemoryRegionInfo::eNo,
121 MemoryRegionInfo::eNo,
122 MemoryRegionInfo::eYes,
123 ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0,
124 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
125 MemoryRegionInfo(
126 make_range(0x7fc094000000, 0x7fc094a00000),
127 MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, MemoryRegionInfo::eNo,
128 MemoryRegionInfo::eYes,
129 MemoryRegionInfo::eYes,
130 ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0,
131 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
132 MemoryRegionInfo(
133 make_range(0xffffffffff600000, 0xffffffffff601000),
134 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
135 MemoryRegionInfo::eNo,
136 MemoryRegionInfo::eYes,
137 ConstString("[vsyscall]"), MemoryRegionInfo::eDontKnow, 0,
138 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
139 },
140 "")));
141
142class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {};
143
144INSTANTIATE_TEST_SUITE_P(
145 ProcSMapTests, LinuxProcSMapsTestFixture,
146 ::testing::Values(
147 // Nothing in nothing out
148 std::make_tuple("", MemoryRegionInfos{}, ""),
149 // Uses the same parsing for first line, so same errors but referring to
150 // smaps
151 std::make_tuple("0/0 rw-p 00000000 00:00 0", MemoryRegionInfos{},
152 "malformed /proc/{pid}/smaps entry, missing dash "
153 "between address range"),
154 // Stop parsing at first error
155 std::make_tuple(
156 "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
157 "0/0 rw-p 00000000 00:00 0",
158 MemoryRegionInfos{
159 MemoryRegionInfo(
160 make_range(0x1111, 0x2222),
161 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
162 MemoryRegionInfo::eNo,
163 MemoryRegionInfo::eYes, ConstString("[foo]"),
164 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
165 MemoryRegionInfo::eDontKnow),
166 },
167 "malformed /proc/{pid}/smaps entry, missing dash between address "
168 "range"),
169 // Property line without a region is an error
170 std::make_tuple("Referenced: 2188 kB\n"
171 "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
172 "3333-4444 rw-p 00000000 00:00 0 [bar]\n",
173 MemoryRegionInfos{},
174 "Found a property line without a corresponding mapping "
175 "in /proc/{pid}/smaps"),
176 // Single region parses, has no flags
177 std::make_tuple(
178 "1111-2222 rw-p 00000000 00:00 0 [foo]",
179 MemoryRegionInfos{
180 MemoryRegionInfo(
181 make_range(0x1111, 0x2222),
182 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
183 MemoryRegionInfo::eNo,
184 MemoryRegionInfo::eYes, ConstString("[foo]"),
185 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
186 MemoryRegionInfo::eDontKnow),
187 },
188 ""),
189 // Single shared region parses, has no flags
190 std::make_tuple(
191 "1111-2222 rw-s 00000000 00:00 0 [foo]",
192 MemoryRegionInfos{
193 MemoryRegionInfo(
194 make_range(0x1111, 0x2222),
195 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
196 MemoryRegionInfo::eYes,
197 MemoryRegionInfo::eYes, ConstString("[foo]"),
198 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
199 MemoryRegionInfo::eDontKnow),
200 },
201 ""),
202 // Single region with flags, other lines ignored
203 std::make_tuple(
204 "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
205 "Referenced: 2188 kB\n"
206 "AnonHugePages: 0 kB\n"
207 "VmFlags: mt",
208 MemoryRegionInfos{
209 MemoryRegionInfo(
210 make_range(0x1111, 0x2222),
211 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
212 MemoryRegionInfo::eNo,
213 MemoryRegionInfo::eYes, ConstString("[foo]"),
214 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes,
215 MemoryRegionInfo::eDontKnow),
216 },
217 ""),
218 // Whitespace ignored
219 std::make_tuple(
220 "0-0 rw-p 00000000 00:00 0\n"
221 "VmFlags: mt ",
222 MemoryRegionInfos{
223 MemoryRegionInfo(make_range(0, 0),
224 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
225 MemoryRegionInfo::eNo,
226 MemoryRegionInfo::eYes, ConstString(nullptr),
227 MemoryRegionInfo::eDontKnow, 0,
228 MemoryRegionInfo::eYes,
229 MemoryRegionInfo::eDontKnow),
230 },
231 ""),
232 // VmFlags line means it has flag info, but nothing is set
233 std::make_tuple(
234 "0-0 rw-p 00000000 00:00 0\n"
235 "VmFlags: ",
236 MemoryRegionInfos{
237 MemoryRegionInfo(make_range(0, 0),
238 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
239 MemoryRegionInfo::eNo,
240 MemoryRegionInfo::eYes, ConstString(nullptr),
241 MemoryRegionInfo::eDontKnow, 0,
242 MemoryRegionInfo::eNo,
243 MemoryRegionInfo::eDontKnow),
244 },
245 ""),
246 // Handle some pages not having a flags line
247 std::make_tuple(
248 "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
249 "Referenced: 2188 kB\n"
250 "AnonHugePages: 0 kB\n"
251 "3333-4444 r-xp 00000000 00:00 0 [bar]\n"
252 "VmFlags: mt",
253 MemoryRegionInfos{
254 MemoryRegionInfo(
255 make_range(0x1111, 0x2222),
256 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
257 MemoryRegionInfo::eNo,
258 MemoryRegionInfo::eYes, ConstString("[foo]"),
259 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
260 MemoryRegionInfo::eDontKnow),
261 MemoryRegionInfo(
262 make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
263 MemoryRegionInfo::eNo,
264 MemoryRegionInfo::eYes, ConstString("[bar]"),
265 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes,
266 MemoryRegionInfo::eDontKnow),
267 },
268 ""),
269 // Handle no pages having a flags line (older kernels)
270 std::make_tuple(
271 "1111-2222 rw-p 00000000 00:00 0\n"
272 "Referenced: 2188 kB\n"
273 "AnonHugePages: 0 kB\n"
274 "3333-4444 r-xp 00000000 00:00 0\n"
275 "KernelPageSize: 4 kB\n"
276 "MMUPageSize: 4 kB\n",
277 MemoryRegionInfos{
278 MemoryRegionInfo(
279 make_range(0x1111, 0x2222),
280 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
281 MemoryRegionInfo::eNo,
282 MemoryRegionInfo::eYes, ConstString(nullptr),
283 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
284 MemoryRegionInfo::eDontKnow),
285 MemoryRegionInfo(
286 make_range(0x3333, 0x4444),
287 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
288 MemoryRegionInfo::eNo,
289 MemoryRegionInfo::eYes, ConstString(nullptr),
290 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
291 MemoryRegionInfo::eDontKnow),
292 },
293 "")));
294
295TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) {
296 auto params = GetParam();
297 ParseLinuxSMapRegions(linux_smap: std::get<0>(t&: params), callback);
298 check_regions(params);
299}
300

source code of lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp