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