proc_maps_linux_unittest.cc 11 KB

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