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_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 258 TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) { 259 auto params = GetParam(); 260 ParseLinuxSMapRegions(std::get<0>(params), callback); 261 check_regions(params); 262 } 263