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