xref: /llvm-project/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp (revision c0702ac07b8e206f424930ff0331151954fb821c)
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(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 
142 class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {};
143 
144 INSTANTIATE_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 
295 TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) {
296   auto params = GetParam();
297   ParseLinuxSMapRegions(std::get<0>(params), callback);
298   check_regions(params);
299 }
300