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