xref: /llvm-project/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp (revision b1751faada35e3456b2a3f6b6c9559b5d74d559b)
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(*Info);
43         return true;
44       }
45 
46       err_str = toString(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(std::get<0>(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(std::get<0>(params), callback);
315   check_regions(params);
316 }
317