132541685SDavid Spickett //===-- LinuxProcMapsTest.cpp ---------------------------------------------===//
232541685SDavid Spickett //
332541685SDavid Spickett // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
432541685SDavid Spickett // See https://llvm.org/LICENSE.txt for license information.
532541685SDavid Spickett // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
632541685SDavid Spickett //
732541685SDavid Spickett //===----------------------------------------------------------------------===//
832541685SDavid Spickett
932541685SDavid Spickett #include "gmock/gmock.h"
1032541685SDavid Spickett #include "gtest/gtest.h"
1132541685SDavid Spickett
1232541685SDavid Spickett #include "Plugins/Process/Utility/LinuxProcMaps.h"
1332541685SDavid Spickett #include "lldb/Target/MemoryRegionInfo.h"
1432541685SDavid Spickett #include "lldb/Utility/Status.h"
1532541685SDavid Spickett #include <tuple>
1632541685SDavid Spickett
1732541685SDavid Spickett using namespace lldb_private;
1832541685SDavid Spickett
1932541685SDavid Spickett typedef std::tuple<const char *, MemoryRegionInfos, const char *>
2032541685SDavid Spickett LinuxProcMapsTestParams;
2132541685SDavid Spickett
2232541685SDavid Spickett // Wrapper for convenience because Range is usually begin, size
make_range(lldb::addr_t begin,lldb::addr_t end)2332541685SDavid Spickett static MemoryRegionInfo::RangeType make_range(lldb::addr_t begin,
2432541685SDavid Spickett lldb::addr_t end) {
2532541685SDavid Spickett MemoryRegionInfo::RangeType range(begin, 0);
2632541685SDavid Spickett range.SetRangeEnd(end);
2732541685SDavid Spickett return range;
2832541685SDavid Spickett }
2932541685SDavid Spickett
3032541685SDavid Spickett class LinuxProcMapsTestFixture
3132541685SDavid Spickett : public ::testing::TestWithParam<LinuxProcMapsTestParams> {
3232541685SDavid Spickett protected:
3332541685SDavid Spickett Status error;
3432541685SDavid Spickett std::string err_str;
3532541685SDavid Spickett MemoryRegionInfos regions;
3632541685SDavid Spickett LinuxMapCallback callback;
3732541685SDavid Spickett
SetUp()3832541685SDavid Spickett void SetUp() override {
3932541685SDavid Spickett callback = [this](llvm::Expected<MemoryRegionInfo> Info) {
4032541685SDavid Spickett if (Info) {
4132541685SDavid Spickett err_str.clear();
4232541685SDavid Spickett regions.push_back(*Info);
4332541685SDavid Spickett return true;
4432541685SDavid Spickett }
4532541685SDavid Spickett
4632541685SDavid Spickett err_str = toString(Info.takeError());
4732541685SDavid Spickett return false;
4832541685SDavid Spickett };
4932541685SDavid Spickett }
5032541685SDavid Spickett
check_regions(LinuxProcMapsTestParams params)5132541685SDavid Spickett void check_regions(LinuxProcMapsTestParams params) {
5232541685SDavid Spickett EXPECT_THAT(std::get<1>(params), testing::ContainerEq(regions));
5332541685SDavid Spickett ASSERT_EQ(std::get<2>(params), err_str);
5432541685SDavid Spickett }
5532541685SDavid Spickett };
5632541685SDavid Spickett
TEST_P(LinuxProcMapsTestFixture,ParseMapRegions)5732541685SDavid Spickett TEST_P(LinuxProcMapsTestFixture, ParseMapRegions) {
5832541685SDavid Spickett auto params = GetParam();
5932541685SDavid Spickett ParseLinuxMapRegions(std::get<0>(params), callback);
6032541685SDavid Spickett check_regions(params);
6132541685SDavid Spickett }
6232541685SDavid Spickett
6332541685SDavid Spickett // Note: ConstString("") != ConstString(nullptr)
6432541685SDavid Spickett // When a region has no name, it will have the latter in the MemoryRegionInfo
65d4d80a29SBenjamin Kramer INSTANTIATE_TEST_SUITE_P(
6632541685SDavid Spickett ProcMapTests, LinuxProcMapsTestFixture,
6732541685SDavid Spickett ::testing::Values(
6832541685SDavid Spickett // Nothing in nothing out
6932541685SDavid Spickett std::make_tuple("", MemoryRegionInfos{}, ""),
7032541685SDavid Spickett // Various formatting error conditions
7132541685SDavid Spickett std::make_tuple("55a4512f7000/55a451b68000 rw-p 00000000 00:00 0",
7232541685SDavid Spickett MemoryRegionInfos{},
7332541685SDavid Spickett "malformed /proc/{pid}/maps entry, missing dash "
7432541685SDavid Spickett "between address range"),
7532541685SDavid Spickett std::make_tuple("0-0 rw", MemoryRegionInfos{},
7632541685SDavid Spickett "malformed /proc/{pid}/maps entry, missing some "
7732541685SDavid Spickett "portion of permissions"),
7832541685SDavid Spickett std::make_tuple("0-0 z--p 00000000 00:00 0", MemoryRegionInfos{},
7932541685SDavid Spickett "unexpected /proc/{pid}/maps read permission char"),
8032541685SDavid Spickett std::make_tuple("0-0 rz-p 00000000 00:00 0", MemoryRegionInfos{},
8132541685SDavid Spickett "unexpected /proc/{pid}/maps write permission char"),
8232541685SDavid Spickett std::make_tuple("0-0 rwzp 00000000 00:00 0", MemoryRegionInfos{},
8332541685SDavid Spickett "unexpected /proc/{pid}/maps exec permission char"),
8432541685SDavid Spickett // Stops at first parsing error
8532541685SDavid Spickett std::make_tuple(
8632541685SDavid Spickett "0-1 rw-p 00000000 00:00 0 [abc]\n"
8732541685SDavid Spickett "0-0 rwzp 00000000 00:00 0\n"
8832541685SDavid Spickett "2-3 r-xp 00000000 00:00 0 [def]\n",
8932541685SDavid Spickett MemoryRegionInfos{
90*c0702ac0SEmre Kultursay MemoryRegionInfo(make_range(0, 1), MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
91*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
9232541685SDavid Spickett MemoryRegionInfo::eYes, ConstString("[abc]"),
9332541685SDavid Spickett MemoryRegionInfo::eDontKnow, 0,
94b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow,
9532541685SDavid Spickett MemoryRegionInfo::eDontKnow),
9632541685SDavid Spickett },
9732541685SDavid Spickett "unexpected /proc/{pid}/maps exec permission char"),
9832541685SDavid Spickett // Single entry
9932541685SDavid Spickett std::make_tuple(
10032541685SDavid Spickett "55a4512f7000-55a451b68000 rw-p 00000000 00:00 0 [heap]",
10132541685SDavid Spickett MemoryRegionInfos{
102b97afc9dSJonas Devlieghere MemoryRegionInfo(
103b97afc9dSJonas Devlieghere make_range(0x55a4512f7000, 0x55a451b68000),
104*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
105*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
106*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes,
107b97afc9dSJonas Devlieghere ConstString("[heap]"), MemoryRegionInfo::eDontKnow, 0,
108b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
10932541685SDavid Spickett },
11032541685SDavid Spickett ""),
11132541685SDavid Spickett // Multiple entries
11232541685SDavid Spickett std::make_tuple(
11332541685SDavid Spickett "7fc090021000-7fc094000000 ---p 00000000 00:00 0\n"
114*c0702ac0SEmre Kultursay "7fc094000000-7fc094a00000 ---s 00000000 00:00 0\n"
11532541685SDavid Spickett "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
11632541685SDavid Spickett "[vsyscall]",
11732541685SDavid Spickett MemoryRegionInfos{
118b97afc9dSJonas Devlieghere MemoryRegionInfo(
119b97afc9dSJonas Devlieghere make_range(0x7fc090021000, 0x7fc094000000),
120*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, MemoryRegionInfo::eNo,
121*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
122*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes,
123*c0702ac0SEmre Kultursay ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0,
124*c0702ac0SEmre Kultursay MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
125*c0702ac0SEmre Kultursay MemoryRegionInfo(
126*c0702ac0SEmre Kultursay make_range(0x7fc094000000, 0x7fc094a00000),
127*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, MemoryRegionInfo::eNo,
128*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes,
129*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes,
130b97afc9dSJonas Devlieghere ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0,
131b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
13232541685SDavid Spickett MemoryRegionInfo(
13332541685SDavid Spickett make_range(0xffffffffff600000, 0xffffffffff601000),
134*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
135*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
136*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes,
13732541685SDavid Spickett ConstString("[vsyscall]"), MemoryRegionInfo::eDontKnow, 0,
138b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow),
13932541685SDavid Spickett },
140d4d80a29SBenjamin Kramer "")));
14132541685SDavid Spickett
14232541685SDavid Spickett class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {};
14332541685SDavid Spickett
144d4d80a29SBenjamin Kramer INSTANTIATE_TEST_SUITE_P(
14532541685SDavid Spickett ProcSMapTests, LinuxProcSMapsTestFixture,
14632541685SDavid Spickett ::testing::Values(
14732541685SDavid Spickett // Nothing in nothing out
14832541685SDavid Spickett std::make_tuple("", MemoryRegionInfos{}, ""),
14932541685SDavid Spickett // Uses the same parsing for first line, so same errors but referring to
15032541685SDavid Spickett // smaps
15132541685SDavid Spickett std::make_tuple("0/0 rw-p 00000000 00:00 0", MemoryRegionInfos{},
15232541685SDavid Spickett "malformed /proc/{pid}/smaps entry, missing dash "
15332541685SDavid Spickett "between address range"),
15432541685SDavid Spickett // Stop parsing at first error
15532541685SDavid Spickett std::make_tuple(
15632541685SDavid Spickett "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
15732541685SDavid Spickett "0/0 rw-p 00000000 00:00 0",
15832541685SDavid Spickett MemoryRegionInfos{
159b97afc9dSJonas Devlieghere MemoryRegionInfo(
160*c0702ac0SEmre Kultursay make_range(0x1111, 0x2222),
161*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
162*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
163b97afc9dSJonas Devlieghere MemoryRegionInfo::eYes, ConstString("[foo]"),
164b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
16532541685SDavid Spickett MemoryRegionInfo::eDontKnow),
16632541685SDavid Spickett },
16732541685SDavid Spickett "malformed /proc/{pid}/smaps entry, missing dash between address "
16832541685SDavid Spickett "range"),
16932541685SDavid Spickett // Property line without a region is an error
17032541685SDavid Spickett std::make_tuple("Referenced: 2188 kB\n"
17132541685SDavid Spickett "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
17232541685SDavid Spickett "3333-4444 rw-p 00000000 00:00 0 [bar]\n",
17332541685SDavid Spickett MemoryRegionInfos{},
17432541685SDavid Spickett "Found a property line without a corresponding mapping "
17532541685SDavid Spickett "in /proc/{pid}/smaps"),
17632541685SDavid Spickett // Single region parses, has no flags
17732541685SDavid Spickett std::make_tuple(
17832541685SDavid Spickett "1111-2222 rw-p 00000000 00:00 0 [foo]",
17932541685SDavid Spickett MemoryRegionInfos{
180b97afc9dSJonas Devlieghere MemoryRegionInfo(
181*c0702ac0SEmre Kultursay make_range(0x1111, 0x2222),
182*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
183*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
184*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, ConstString("[foo]"),
185*c0702ac0SEmre Kultursay MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
186*c0702ac0SEmre Kultursay MemoryRegionInfo::eDontKnow),
187*c0702ac0SEmre Kultursay },
188*c0702ac0SEmre Kultursay ""),
189*c0702ac0SEmre Kultursay // Single shared region parses, has no flags
190*c0702ac0SEmre Kultursay std::make_tuple(
191*c0702ac0SEmre Kultursay "1111-2222 rw-s 00000000 00:00 0 [foo]",
192*c0702ac0SEmre Kultursay MemoryRegionInfos{
193*c0702ac0SEmre Kultursay MemoryRegionInfo(
194*c0702ac0SEmre Kultursay make_range(0x1111, 0x2222),
195*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
196*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes,
197b97afc9dSJonas Devlieghere MemoryRegionInfo::eYes, ConstString("[foo]"),
198b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
19932541685SDavid Spickett MemoryRegionInfo::eDontKnow),
20032541685SDavid Spickett },
20132541685SDavid Spickett ""),
20232541685SDavid Spickett // Single region with flags, other lines ignored
20332541685SDavid Spickett std::make_tuple(
20432541685SDavid Spickett "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
20532541685SDavid Spickett "Referenced: 2188 kB\n"
20632541685SDavid Spickett "AnonHugePages: 0 kB\n"
20732541685SDavid Spickett "VmFlags: mt",
20832541685SDavid Spickett MemoryRegionInfos{
20932541685SDavid Spickett MemoryRegionInfo(
210*c0702ac0SEmre Kultursay make_range(0x1111, 0x2222),
211*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
212*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
21332541685SDavid Spickett MemoryRegionInfo::eYes, ConstString("[foo]"),
214b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes,
215b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow),
21632541685SDavid Spickett },
21732541685SDavid Spickett ""),
21832541685SDavid Spickett // Whitespace ignored
21932541685SDavid Spickett std::make_tuple(
22032541685SDavid Spickett "0-0 rw-p 00000000 00:00 0\n"
22132541685SDavid Spickett "VmFlags: mt ",
22232541685SDavid Spickett MemoryRegionInfos{
223*c0702ac0SEmre Kultursay MemoryRegionInfo(make_range(0, 0),
224*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
225*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
22632541685SDavid Spickett MemoryRegionInfo::eYes, ConstString(nullptr),
22732541685SDavid Spickett MemoryRegionInfo::eDontKnow, 0,
228b97afc9dSJonas Devlieghere MemoryRegionInfo::eYes,
229b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow),
23032541685SDavid Spickett },
23132541685SDavid Spickett ""),
23232541685SDavid Spickett // VmFlags line means it has flag info, but nothing is set
23332541685SDavid Spickett std::make_tuple(
23432541685SDavid Spickett "0-0 rw-p 00000000 00:00 0\n"
23532541685SDavid Spickett "VmFlags: ",
23632541685SDavid Spickett MemoryRegionInfos{
237*c0702ac0SEmre Kultursay MemoryRegionInfo(make_range(0, 0),
238*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
239*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
24032541685SDavid Spickett MemoryRegionInfo::eYes, ConstString(nullptr),
24132541685SDavid Spickett MemoryRegionInfo::eDontKnow, 0,
242b97afc9dSJonas Devlieghere MemoryRegionInfo::eNo,
243b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow),
24432541685SDavid Spickett },
24532541685SDavid Spickett ""),
24632541685SDavid Spickett // Handle some pages not having a flags line
24732541685SDavid Spickett std::make_tuple(
24832541685SDavid Spickett "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
24932541685SDavid Spickett "Referenced: 2188 kB\n"
25032541685SDavid Spickett "AnonHugePages: 0 kB\n"
25132541685SDavid Spickett "3333-4444 r-xp 00000000 00:00 0 [bar]\n"
25232541685SDavid Spickett "VmFlags: mt",
25332541685SDavid Spickett MemoryRegionInfos{
254b97afc9dSJonas Devlieghere MemoryRegionInfo(
255*c0702ac0SEmre Kultursay make_range(0x1111, 0x2222),
256*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
257*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
258b97afc9dSJonas Devlieghere MemoryRegionInfo::eYes, ConstString("[foo]"),
259b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
26032541685SDavid Spickett MemoryRegionInfo::eDontKnow),
26132541685SDavid Spickett MemoryRegionInfo(
262*c0702ac0SEmre Kultursay make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
263*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
26432541685SDavid Spickett MemoryRegionInfo::eYes, ConstString("[bar]"),
265b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes,
266b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow),
26732541685SDavid Spickett },
26832541685SDavid Spickett ""),
26932541685SDavid Spickett // Handle no pages having a flags line (older kernels)
27032541685SDavid Spickett std::make_tuple(
27132541685SDavid Spickett "1111-2222 rw-p 00000000 00:00 0\n"
27232541685SDavid Spickett "Referenced: 2188 kB\n"
27332541685SDavid Spickett "AnonHugePages: 0 kB\n"
27432541685SDavid Spickett "3333-4444 r-xp 00000000 00:00 0\n"
27532541685SDavid Spickett "KernelPageSize: 4 kB\n"
27632541685SDavid Spickett "MMUPageSize: 4 kB\n",
27732541685SDavid Spickett MemoryRegionInfos{
278b97afc9dSJonas Devlieghere MemoryRegionInfo(
279*c0702ac0SEmre Kultursay make_range(0x1111, 0x2222),
280*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
281*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
282b97afc9dSJonas Devlieghere MemoryRegionInfo::eYes, ConstString(nullptr),
283b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
284b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow),
285b97afc9dSJonas Devlieghere MemoryRegionInfo(
286*c0702ac0SEmre Kultursay make_range(0x3333, 0x4444),
287*c0702ac0SEmre Kultursay MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
288*c0702ac0SEmre Kultursay MemoryRegionInfo::eNo,
289b97afc9dSJonas Devlieghere MemoryRegionInfo::eYes, ConstString(nullptr),
290b97afc9dSJonas Devlieghere MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow,
29132541685SDavid Spickett MemoryRegionInfo::eDontKnow),
29232541685SDavid Spickett },
293d4d80a29SBenjamin Kramer "")));
29432541685SDavid Spickett
TEST_P(LinuxProcSMapsTestFixture,ParseSMapRegions)29532541685SDavid Spickett TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) {
29632541685SDavid Spickett auto params = GetParam();
29732541685SDavid Spickett ParseLinuxSMapRegions(std::get<0>(params), callback);
29832541685SDavid Spickett check_regions(params);
29932541685SDavid Spickett }
300