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( 91 make_range(0, 1), MemoryRegionInfo::eYes, 92 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 93 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 94 ConstString("[abc]"), MemoryRegionInfo::eDontKnow, 0, 95 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, 96 MemoryRegionInfo::eDontKnow), 97 }, 98 "unexpected /proc/{pid}/maps exec permission char"), 99 // Single entry 100 std::make_tuple( 101 "55a4512f7000-55a451b68000 rw-p 00000000 00:00 0 [heap]", 102 MemoryRegionInfos{ 103 MemoryRegionInfo( 104 make_range(0x55a4512f7000, 0x55a451b68000), 105 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, 106 MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, 107 MemoryRegionInfo::eYes, ConstString("[heap]"), 108 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, 109 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), 110 }, 111 ""), 112 // Multiple entries 113 std::make_tuple( 114 "7fc090021000-7fc094000000 ---p 00000000 00:00 0\n" 115 "7fc094000000-7fc094a00000 ---s 00000000 00:00 0\n" 116 "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 " 117 "[vsyscall]", 118 MemoryRegionInfos{ 119 MemoryRegionInfo( 120 make_range(0x7fc090021000, 0x7fc094000000), 121 MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, 122 MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, 123 MemoryRegionInfo::eYes, ConstString(nullptr), 124 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, 125 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), 126 MemoryRegionInfo( 127 make_range(0x7fc094000000, 0x7fc094a00000), 128 MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, 129 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 130 MemoryRegionInfo::eYes, ConstString(nullptr), 131 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, 132 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), 133 MemoryRegionInfo( 134 make_range(0xffffffffff600000, 0xffffffffff601000), 135 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 136 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 137 MemoryRegionInfo::eYes, ConstString("[vsyscall]"), 138 MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, 139 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), 140 }, 141 ""))); 142 143 class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {}; 144 145 INSTANTIATE_TEST_SUITE_P( 146 ProcSMapTests, LinuxProcSMapsTestFixture, 147 ::testing::Values( 148 // Nothing in nothing out 149 std::make_tuple("", MemoryRegionInfos{}, ""), 150 // Uses the same parsing for first line, so same errors but referring to 151 // smaps 152 std::make_tuple("0/0 rw-p 00000000 00:00 0", MemoryRegionInfos{}, 153 "malformed /proc/{pid}/smaps entry, missing dash " 154 "between address range"), 155 // Stop parsing at first error 156 std::make_tuple( 157 "1111-2222 rw-p 00000000 00:00 0 [foo]\n" 158 "0/0 rw-p 00000000 00:00 0", 159 MemoryRegionInfos{ 160 MemoryRegionInfo( 161 make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, 162 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 163 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 164 ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, 165 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, 166 MemoryRegionInfo::eDontKnow), 167 }, 168 "malformed /proc/{pid}/smaps entry, missing dash between address " 169 "range"), 170 // Property line without a region is an error 171 std::make_tuple("Referenced: 2188 kB\n" 172 "1111-2222 rw-p 00000000 00:00 0 [foo]\n" 173 "3333-4444 rw-p 00000000 00:00 0 [bar]\n", 174 MemoryRegionInfos{}, 175 "Found a property line without a corresponding mapping " 176 "in /proc/{pid}/smaps"), 177 // Single region parses, has no flags 178 std::make_tuple( 179 "1111-2222 rw-p 00000000 00:00 0 [foo]", 180 MemoryRegionInfos{ 181 MemoryRegionInfo( 182 make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, 183 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 184 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 185 ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, 186 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, 187 MemoryRegionInfo::eDontKnow), 188 }, 189 ""), 190 // Single shared region parses, has no flags 191 std::make_tuple( 192 "1111-2222 rw-s 00000000 00:00 0 [foo]", 193 MemoryRegionInfos{ 194 MemoryRegionInfo( 195 make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, 196 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 197 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, 198 ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, 199 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, 200 MemoryRegionInfo::eDontKnow), 201 }, 202 ""), 203 // Single region with flags, other lines ignored 204 std::make_tuple( 205 "1111-2222 rw-p 00000000 00:00 0 [foo]\n" 206 "Referenced: 2188 kB\n" 207 "AnonHugePages: 0 kB\n" 208 "VmFlags: mt", 209 MemoryRegionInfos{ 210 MemoryRegionInfo( 211 make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, 212 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 213 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 214 ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, 215 MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, 216 MemoryRegionInfo::eNo), 217 }, 218 ""), 219 // Whitespace ignored 220 std::make_tuple( 221 "0-0 rw-p 00000000 00:00 0\n" 222 "VmFlags: mt ", 223 MemoryRegionInfos{ 224 MemoryRegionInfo( 225 make_range(0, 0), MemoryRegionInfo::eYes, 226 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 227 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 228 ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, 229 MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, 230 MemoryRegionInfo::eNo), 231 }, 232 ""), 233 // VmFlags line means it has flag info, but nothing is set 234 std::make_tuple( 235 "0-0 rw-p 00000000 00:00 0\n" 236 "VmFlags: ", 237 MemoryRegionInfos{ 238 MemoryRegionInfo( 239 make_range(0, 0), MemoryRegionInfo::eYes, 240 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 241 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 242 ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, 243 MemoryRegionInfo::eNo, MemoryRegionInfo::eDontKnow, 244 MemoryRegionInfo::eNo), 245 }, 246 ""), 247 // Handle some pages not having a flags line 248 std::make_tuple( 249 "1111-2222 rw-p 00000000 00:00 0 [foo]\n" 250 "Referenced: 2188 kB\n" 251 "AnonHugePages: 0 kB\n" 252 "3333-4444 r-xp 00000000 00:00 0 [bar]\n" 253 "VmFlags: mt", 254 MemoryRegionInfos{ 255 MemoryRegionInfo( 256 make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, 257 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 258 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 259 ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, 260 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, 261 MemoryRegionInfo::eDontKnow), 262 MemoryRegionInfo( 263 make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, 264 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 265 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 266 ConstString("[bar]"), MemoryRegionInfo::eDontKnow, 0, 267 MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, 268 MemoryRegionInfo::eNo), 269 }, 270 ""), 271 // Handle no pages having a flags line (older kernels) 272 std::make_tuple( 273 "1111-2222 rw-p 00000000 00:00 0\n" 274 "Referenced: 2188 kB\n" 275 "AnonHugePages: 0 kB\n" 276 "3333-4444 r-xp 00000000 00:00 0\n" 277 "KernelPageSize: 4 kB\n" 278 "MMUPageSize: 4 kB\n", 279 MemoryRegionInfos{ 280 MemoryRegionInfo( 281 make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, 282 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 283 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 284 ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, 285 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, 286 MemoryRegionInfo::eDontKnow), 287 MemoryRegionInfo( 288 make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, 289 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 290 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 291 ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, 292 MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, 293 MemoryRegionInfo::eDontKnow), 294 }, 295 ""), 296 // We must look for exact flag strings, ignoring substrings of longer 297 // flag names. 298 std::make_tuple( 299 "0-0 rw-p 00000000 00:00 0\n" 300 "VmFlags: amt mtb amtb", 301 MemoryRegionInfos{ 302 MemoryRegionInfo( 303 make_range(0, 0), MemoryRegionInfo::eYes, 304 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, 305 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, 306 ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, 307 MemoryRegionInfo::eNo, MemoryRegionInfo::eDontKnow, 308 MemoryRegionInfo::eNo), 309 }, 310 ""))); 311 312 TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) { 313 auto params = GetParam(); 314 ParseLinuxSMapRegions(std::get<0>(params), callback); 315 check_regions(params); 316 } 317