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,
91                                  MemoryRegionInfo::eYes, 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,
105                     MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
106                     ConstString("[heap]"), MemoryRegionInfo::eDontKnow, 0,
107                     MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
108             },
109             ""),
110         // Multiple entries
111         std::make_tuple(
112             "7fc090021000-7fc094000000 ---p 00000000 00:00 0\n"
113             "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
114             "[vsyscall]",
115             MemoryRegionInfos{
116                 MemoryRegionInfo(
117                     make_range(0x7fc090021000, 0x7fc094000000),
118                     MemoryRegionInfo::eNo, MemoryRegionInfo::eNo,
119                     MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
120                     ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0,
121                     MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
122                 MemoryRegionInfo(
123                     make_range(0xffffffffff600000, 0xffffffffff601000),
124                     MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
125                     MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
126                     ConstString("[vsyscall]"), MemoryRegionInfo::eDontKnow, 0,
127                     MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
128             },
129             "")));
130 
131 class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {};
132 
133 INSTANTIATE_TEST_SUITE_P(
134     ProcSMapTests, LinuxProcSMapsTestFixture,
135     ::testing::Values(
136         // Nothing in nothing out
137         std::make_tuple("", MemoryRegionInfos{}, ""),
138         // Uses the same parsing for first line, so same errors but referring to
139         // smaps
140         std::make_tuple("0/0 rw-p 00000000 00:00 0", MemoryRegionInfos{},
141                         "malformed /proc/{pid}/smaps entry, missing dash "
142                         "between address range"),
143         // Stop parsing at first error
144         std::make_tuple(
145             "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
146             "0/0 rw-p 00000000 00:00 0",
147             MemoryRegionInfos{
148                 MemoryRegionInfo(
149                     make_range(0x1111, 0x2222), MemoryRegionInfo::eYes,
150                     MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
151                     MemoryRegionInfo::eYes, ConstString("[foo]"),
152                     MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
153                     MemoryRegionInfo::eDontKnow),
154             },
155             "malformed /proc/{pid}/smaps entry, missing dash between address "
156             "range"),
157         // Property line without a region is an error
158         std::make_tuple("Referenced:         2188 kB\n"
159                         "1111-2222 rw-p 00000000 00:00 0    [foo]\n"
160                         "3333-4444 rw-p 00000000 00:00 0    [bar]\n",
161                         MemoryRegionInfos{},
162                         "Found a property line without a corresponding mapping "
163                         "in /proc/{pid}/smaps"),
164         // Single region parses, has no flags
165         std::make_tuple(
166             "1111-2222 rw-p 00000000 00:00 0    [foo]",
167             MemoryRegionInfos{
168                 MemoryRegionInfo(
169                     make_range(0x1111, 0x2222), MemoryRegionInfo::eYes,
170                     MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
171                     MemoryRegionInfo::eYes, ConstString("[foo]"),
172                     MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
173                     MemoryRegionInfo::eDontKnow),
174             },
175             ""),
176         // Single region with flags, other lines ignored
177         std::make_tuple(
178             "1111-2222 rw-p 00000000 00:00 0    [foo]\n"
179             "Referenced:         2188 kB\n"
180             "AnonHugePages:         0 kB\n"
181             "VmFlags: mt",
182             MemoryRegionInfos{
183                 MemoryRegionInfo(
184                     make_range(0x1111, 0x2222), MemoryRegionInfo::eYes,
185                     MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
186                     MemoryRegionInfo::eYes, ConstString("[foo]"),
187                     MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes,
188                     MemoryRegionInfo::eDontKnow),
189             },
190             ""),
191         // Whitespace ignored
192         std::make_tuple(
193             "0-0 rw-p 00000000 00:00 0\n"
194             "VmFlags:      mt      ",
195             MemoryRegionInfos{
196                 MemoryRegionInfo(make_range(0, 0), MemoryRegionInfo::eYes,
197                                  MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
198                                  MemoryRegionInfo::eYes, ConstString(nullptr),
199                                  MemoryRegionInfo::eDontKnow, 0,
200                                  MemoryRegionInfo::eYes,
201                                  MemoryRegionInfo::eDontKnow),
202             },
203             ""),
204         // VmFlags line means it has flag info, but nothing is set
205         std::make_tuple(
206             "0-0 rw-p 00000000 00:00 0\n"
207             "VmFlags:         ",
208             MemoryRegionInfos{
209                 MemoryRegionInfo(make_range(0, 0), MemoryRegionInfo::eYes,
210                                  MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
211                                  MemoryRegionInfo::eYes, ConstString(nullptr),
212                                  MemoryRegionInfo::eDontKnow, 0,
213                                  MemoryRegionInfo::eNo,
214                                  MemoryRegionInfo::eDontKnow),
215             },
216             ""),
217         // Handle some pages not having a flags line
218         std::make_tuple(
219             "1111-2222 rw-p 00000000 00:00 0    [foo]\n"
220             "Referenced:         2188 kB\n"
221             "AnonHugePages:         0 kB\n"
222             "3333-4444 r-xp 00000000 00:00 0    [bar]\n"
223             "VmFlags: mt",
224             MemoryRegionInfos{
225                 MemoryRegionInfo(
226                     make_range(0x1111, 0x2222), MemoryRegionInfo::eYes,
227                     MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
228                     MemoryRegionInfo::eYes, ConstString("[foo]"),
229                     MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
230                     MemoryRegionInfo::eDontKnow),
231                 MemoryRegionInfo(
232                     make_range(0x3333, 0x4444), MemoryRegionInfo::eYes,
233                     MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
234                     MemoryRegionInfo::eYes, ConstString("[bar]"),
235                     MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes,
236                     MemoryRegionInfo::eDontKnow),
237             },
238             ""),
239         // Handle no pages having a flags line (older kernels)
240         std::make_tuple(
241             "1111-2222 rw-p 00000000 00:00 0\n"
242             "Referenced:         2188 kB\n"
243             "AnonHugePages:         0 kB\n"
244             "3333-4444 r-xp 00000000 00:00 0\n"
245             "KernelPageSize:        4 kB\n"
246             "MMUPageSize:           4 kB\n",
247             MemoryRegionInfos{
248                 MemoryRegionInfo(
249                     make_range(0x1111, 0x2222), MemoryRegionInfo::eYes,
250                     MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
251                     MemoryRegionInfo::eYes, ConstString(nullptr),
252                     MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
253                     MemoryRegionInfo::eDontKnow),
254                 MemoryRegionInfo(
255                     make_range(0x3333, 0x4444), MemoryRegionInfo::eYes,
256                     MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
257                     MemoryRegionInfo::eYes, ConstString(nullptr),
258                     MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
259                     MemoryRegionInfo::eDontKnow),
260             },
261             "")));
262 
263 TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) {
264   auto params = GetParam();
265   ParseLinuxSMapRegions(std::get<0>(params), callback);
266   check_regions(params);
267 }
268