1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/debug/proc_maps_linux.h" 6 #include "base/files/file_path.h" 7 #include "base/path_service.h" 8 #include "base/strings/stringprintf.h" 9 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace base { 13 namespace debug { 14 15 TEST(ProcMapsTest, Empty) { 16 std::vector<MappedMemoryRegion> regions; 17 EXPECT_TRUE(ParseProcMaps("", ®ions)); 18 EXPECT_EQ(0u, regions.size()); 19 } 20 21 TEST(ProcMapsTest, NoSpaces) { 22 static const char kNoSpaces[] = 23 "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n"; 24 25 std::vector<MappedMemoryRegion> regions; 26 ASSERT_TRUE(ParseProcMaps(kNoSpaces, ®ions)); 27 ASSERT_EQ(1u, regions.size()); 28 29 EXPECT_EQ(0x00400000u, regions[0].start); 30 EXPECT_EQ(0x0040b000u, regions[0].end); 31 EXPECT_EQ(0x00002200u, regions[0].offset); 32 EXPECT_EQ("/bin/cat", regions[0].path); 33 } 34 35 TEST(ProcMapsTest, Spaces) { 36 static const char kSpaces[] = 37 "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n"; 38 39 std::vector<MappedMemoryRegion> regions; 40 ASSERT_TRUE(ParseProcMaps(kSpaces, ®ions)); 41 ASSERT_EQ(1u, regions.size()); 42 43 EXPECT_EQ(0x00400000u, regions[0].start); 44 EXPECT_EQ(0x0040b000u, regions[0].end); 45 EXPECT_EQ(0x00002200u, regions[0].offset); 46 EXPECT_EQ("/bin/space cat", regions[0].path); 47 } 48 49 TEST(ProcMapsTest, NoNewline) { 50 static const char kNoSpaces[] = 51 "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat"; 52 53 std::vector<MappedMemoryRegion> regions; 54 ASSERT_FALSE(ParseProcMaps(kNoSpaces, ®ions)); 55 } 56 57 TEST(ProcMapsTest, NoPath) { 58 static const char kNoPath[] = 59 "00400000-0040b000 rw-p 00000000 00:00 0 \n"; 60 61 std::vector<MappedMemoryRegion> regions; 62 ASSERT_TRUE(ParseProcMaps(kNoPath, ®ions)); 63 ASSERT_EQ(1u, regions.size()); 64 65 EXPECT_EQ(0x00400000u, regions[0].start); 66 EXPECT_EQ(0x0040b000u, regions[0].end); 67 EXPECT_EQ(0x00000000u, regions[0].offset); 68 EXPECT_EQ("", regions[0].path); 69 } 70 71 TEST(ProcMapsTest, Heap) { 72 static const char kHeap[] = 73 "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n"; 74 75 std::vector<MappedMemoryRegion> regions; 76 ASSERT_TRUE(ParseProcMaps(kHeap, ®ions)); 77 ASSERT_EQ(1u, regions.size()); 78 79 EXPECT_EQ(0x022ac000u, regions[0].start); 80 EXPECT_EQ(0x022cd000u, regions[0].end); 81 EXPECT_EQ(0x00000000u, regions[0].offset); 82 EXPECT_EQ("[heap]", regions[0].path); 83 } 84 85 #if defined(ARCH_CPU_32_BITS) 86 TEST(ProcMapsTest, Stack32) { 87 static const char kStack[] = 88 "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n"; 89 90 std::vector<MappedMemoryRegion> regions; 91 ASSERT_TRUE(ParseProcMaps(kStack, ®ions)); 92 ASSERT_EQ(1u, regions.size()); 93 94 EXPECT_EQ(0xbeb04000u, regions[0].start); 95 EXPECT_EQ(0xbeb25000u, regions[0].end); 96 EXPECT_EQ(0x00000000u, regions[0].offset); 97 EXPECT_EQ("[stack]", regions[0].path); 98 } 99 #elif defined(ARCH_CPU_64_BITS) 100 TEST(ProcMapsTest, Stack64) { 101 static const char kStack[] = 102 "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n"; 103 104 std::vector<MappedMemoryRegion> regions; 105 ASSERT_TRUE(ParseProcMaps(kStack, ®ions)); 106 ASSERT_EQ(1u, regions.size()); 107 108 EXPECT_EQ(0x7fff69c5b000u, regions[0].start); 109 EXPECT_EQ(0x7fff69c7d000u, regions[0].end); 110 EXPECT_EQ(0x00000000u, regions[0].offset); 111 EXPECT_EQ("[stack]", regions[0].path); 112 } 113 #endif 114 115 TEST(ProcMapsTest, Multiple) { 116 static const char kMultiple[] = 117 "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n" 118 "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n" 119 "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n"; 120 121 std::vector<MappedMemoryRegion> regions; 122 ASSERT_TRUE(ParseProcMaps(kMultiple, ®ions)); 123 ASSERT_EQ(3u, regions.size()); 124 125 EXPECT_EQ(0x00400000u, regions[0].start); 126 EXPECT_EQ(0x0040b000u, regions[0].end); 127 EXPECT_EQ(0x00000000u, regions[0].offset); 128 EXPECT_EQ("/bin/cat", regions[0].path); 129 130 EXPECT_EQ(0x0060a000u, regions[1].start); 131 EXPECT_EQ(0x0060b000u, regions[1].end); 132 EXPECT_EQ(0x0000a000u, regions[1].offset); 133 EXPECT_EQ("/bin/cat", regions[1].path); 134 135 EXPECT_EQ(0x0060b000u, regions[2].start); 136 EXPECT_EQ(0x0060c000u, regions[2].end); 137 EXPECT_EQ(0x0000b000u, regions[2].offset); 138 EXPECT_EQ("/bin/cat", regions[2].path); 139 } 140 141 TEST(ProcMapsTest, Permissions) { 142 static struct { 143 const char* input; 144 uint8 permissions; 145 } kTestCases[] = { 146 {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0}, 147 {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0}, 148 {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n", 149 MappedMemoryRegion::READ}, 150 {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n", 151 MappedMemoryRegion::WRITE}, 152 {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n", 153 MappedMemoryRegion::EXECUTE}, 154 {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n", 155 MappedMemoryRegion::READ | MappedMemoryRegion::WRITE | 156 MappedMemoryRegion::EXECUTE}, 157 {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n", 158 MappedMemoryRegion::PRIVATE}, 159 {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n", 160 MappedMemoryRegion::READ | MappedMemoryRegion::PRIVATE}, 161 {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n", 162 MappedMemoryRegion::WRITE | MappedMemoryRegion::PRIVATE}, 163 {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n", 164 MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE}, 165 {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n", 166 MappedMemoryRegion::READ | MappedMemoryRegion::WRITE | 167 MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE}, 168 }; 169 170 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { 171 SCOPED_TRACE( 172 base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i].input)); 173 174 std::vector<MappedMemoryRegion> regions; 175 EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, ®ions)); 176 EXPECT_EQ(1u, regions.size()); 177 if (regions.empty()) 178 continue; 179 EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions); 180 } 181 } 182 183 // ProcMapsTest.ReadProcMaps fails under TSan on Linux, 184 // see http://crbug.com/258451. 185 #if defined(THREAD_SANITIZER) 186 #define MAYBE_ReadProcMaps DISABLED_ReadProcMaps 187 #else 188 #define MAYBE_ReadProcMaps ReadProcMaps 189 #endif 190 TEST(ProcMapsTest, MAYBE_ReadProcMaps) { 191 std::string proc_maps; 192 ASSERT_TRUE(ReadProcMaps(&proc_maps)); 193 194 std::vector<MappedMemoryRegion> regions; 195 ASSERT_TRUE(ParseProcMaps(proc_maps, ®ions)); 196 ASSERT_FALSE(regions.empty()); 197 198 // We should be able to find both the current executable as well as the stack 199 // mapped into memory. Use the address of |proc_maps| as a way of finding the 200 // stack. 201 FilePath exe_path; 202 EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path)); 203 uintptr_t address = reinterpret_cast<uintptr_t>(&proc_maps); 204 bool found_exe = false; 205 bool found_stack = false; 206 bool found_address = false; 207 for (size_t i = 0; i < regions.size(); ++i) { 208 if (regions[i].path == exe_path.value()) { 209 // It's OK to find the executable mapped multiple times as there'll be 210 // multiple sections (e.g., text, data). 211 found_exe = true; 212 } 213 214 if (regions[i].path == "[stack]") { 215 // Only check if |address| lies within the real stack when not running 216 // Valgrind, otherwise |address| will be on a stack that Valgrind creates. 217 if (!RunningOnValgrind()) { 218 EXPECT_GE(address, regions[i].start); 219 EXPECT_LT(address, regions[i].end); 220 } 221 222 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ); 223 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE); 224 EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE); 225 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE); 226 EXPECT_FALSE(found_stack) << "Found duplicate stacks"; 227 found_stack = true; 228 } 229 230 if (address >= regions[i].start && address < regions[i].end) { 231 EXPECT_FALSE(found_address) << "Found same address in multiple regions"; 232 found_address = true; 233 } 234 } 235 236 EXPECT_TRUE(found_exe); 237 EXPECT_TRUE(found_stack); 238 EXPECT_TRUE(found_address); 239 } 240 241 TEST(ProcMapsTest, MissingFields) { 242 static const char* kTestCases[] = { 243 "00400000\n", // Missing end + beyond. 244 "00400000-0040b000\n", // Missing perms + beyond. 245 "00400000-0040b000 r-xp\n", // Missing offset + beyond. 246 "00400000-0040b000 r-xp 00000000\n", // Missing device + beyond. 247 "00400000-0040b000 r-xp 00000000 fc:00\n", // Missing inode + beyond. 248 "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n", // Missing perms. 249 "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n", // Missing offset. 250 "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n", // Missing inode. 251 "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing end. 252 "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing start. 253 "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n", // Missing device. 254 }; 255 256 for (size_t i = 0; i < arraysize(kTestCases); ++i) { 257 SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i])); 258 std::vector<MappedMemoryRegion> regions; 259 EXPECT_FALSE(ParseProcMaps(kTestCases[i], ®ions)); 260 } 261 } 262 263 TEST(ProcMapsTest, InvalidInput) { 264 static const char* kTestCases[] = { 265 "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n", 266 "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n", 267 "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n", 268 "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n", 269 "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n", 270 "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n", 271 }; 272 273 for (size_t i = 0; i < arraysize(kTestCases); ++i) { 274 SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i])); 275 std::vector<MappedMemoryRegion> regions; 276 EXPECT_FALSE(ParseProcMaps(kTestCases[i], ®ions)); 277 } 278 } 279 280 } // namespace debug 281 } // namespace base 282