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