317 lines · cpp
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-exception6//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 17using namespace lldb_private;18 19typedef std::tuple<const char *, MemoryRegionInfos, const char *>20 LinuxProcMapsTestParams;21 22// Wrapper for convenience because Range is usually begin, size23static 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 30class LinuxProcMapsTestFixture31 : public ::testing::TestWithParam<LinuxProcMapsTestParams> {32protected: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 57TEST_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 MemoryRegionInfo65INSTANTIATE_TEST_SUITE_P(66 ProcMapTests, LinuxProcMapsTestFixture,67 ::testing::Values(68 // Nothing in nothing out69 std::make_tuple("", MemoryRegionInfos{}, ""),70 // Various formatting error conditions71 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 error85 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 entry100 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 entries113 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 143class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {};144 145INSTANTIATE_TEST_SUITE_P(146 ProcSMapTests, LinuxProcSMapsTestFixture,147 ::testing::Values(148 // Nothing in nothing out149 std::make_tuple("", MemoryRegionInfos{}, ""),150 // Uses the same parsing for first line, so same errors but referring to151 // smaps152 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 error156 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 error171 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 flags178 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 flags191 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 ignored204 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 ignored220 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 set234 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 line248 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 longer297 // 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 312TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) {313 auto params = GetParam();314 ParseLinuxSMapRegions(std::get<0>(params), callback);315 check_regions(params);316}317