OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/proc_maps_linux.h" | 5 #include "base/debug/proc_maps_linux.h" |
6 | 6 |
| 7 #include <fcntl.h> |
| 8 |
7 #if defined(OS_LINUX) | 9 #if defined(OS_LINUX) |
8 #include <inttypes.h> | 10 #include <inttypes.h> |
9 #endif | 11 #endif |
10 | 12 |
11 #include "base/file_util.h" | 13 #include "base/file_util.h" |
12 #include "base/strings/string_split.h" | 14 #include "base/strings/string_split.h" |
13 | 15 |
14 #if defined(OS_ANDROID) | 16 #if defined(OS_ANDROID) |
15 // Bionic's inttypes.h defines PRI/SCNxPTR as an unsigned long int, which | 17 // Bionic's inttypes.h defines PRI/SCNxPTR as an unsigned long int, which |
16 // is incompatible with Bionic's stdint.h defining uintptr_t as a unsigned int: | 18 // is incompatible with Bionic's stdint.h defining uintptr_t as a unsigned int: |
17 // https://code.google.com/p/android/issues/detail?id=57218 | 19 // https://code.google.com/p/android/issues/detail?id=57218 |
18 #undef SCNxPTR | 20 #undef SCNxPTR |
19 #define SCNxPTR "x" | 21 #define SCNxPTR "x" |
20 #endif | 22 #endif |
21 | 23 |
22 namespace base { | 24 namespace base { |
23 namespace debug { | 25 namespace debug { |
24 | 26 |
| 27 // Scans |proc_maps| starting from |pos| returning true if the gate VMA was |
| 28 // found, otherwise returns false. |
| 29 static bool ContainsGateVMA(std::string* proc_maps, size_t pos) { |
| 30 #if defined(ARCH_CPU_ARM_FAMILY) |
| 31 // The gate VMA on ARM kernels is the interrupt vectors page. |
| 32 return proc_maps->find(" [vectors]\n", pos) != std::string::npos; |
| 33 #elif defined(ARCH_CPU_X86_64) |
| 34 // The gate VMA on x86 64-bit kernels is the virtual system call page. |
| 35 return proc_maps->find(" [vsyscall]\n", pos) != std::string::npos; |
| 36 #else |
| 37 // Otherwise assume there is no gate VMA in which case we shouldn't |
| 38 // get duplicate entires. |
| 39 return false; |
| 40 #endif |
| 41 } |
| 42 |
25 bool ReadProcMaps(std::string* proc_maps) { | 43 bool ReadProcMaps(std::string* proc_maps) { |
26 FilePath proc_maps_path("/proc/self/maps"); | 44 // seq_file only writes out a page-sized amount on each call. Refer to header |
27 return ReadFileToString(proc_maps_path, proc_maps); | 45 // file for details. |
| 46 const long kReadSize = sysconf(_SC_PAGESIZE); |
| 47 |
| 48 int fd = HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)); |
| 49 if (fd == -1) { |
| 50 DPLOG(ERROR) << "Couldn't open /proc/self/maps"; |
| 51 return false; |
| 52 } |
| 53 file_util::ScopedFD fd_closer(&fd); |
| 54 proc_maps->clear(); |
| 55 |
| 56 while (true) { |
| 57 // To avoid a copy, resize |proc_maps| so read() can write directly into it. |
| 58 // Compute |buffer| afterwards since resize() may reallocate. |
| 59 size_t pos = proc_maps->size(); |
| 60 proc_maps->resize(pos + kReadSize); |
| 61 void* buffer = &(*proc_maps)[pos]; |
| 62 |
| 63 ssize_t bytes_read = HANDLE_EINTR(read(fd, buffer, kReadSize)); |
| 64 if (bytes_read < 0) { |
| 65 DPLOG(ERROR) << "Couldn't read /proc/self/maps"; |
| 66 proc_maps->clear(); |
| 67 return false; |
| 68 } |
| 69 |
| 70 // ... and don't forget to trim off excess bytes. |
| 71 proc_maps->resize(pos + bytes_read); |
| 72 |
| 73 if (bytes_read == 0) |
| 74 break; |
| 75 |
| 76 // The gate VMA is handled as a special case after seq_file has finished |
| 77 // iterating through all entries in the virtual memory table. |
| 78 // |
| 79 // Unfortunately, if additional entries are added at this point in time |
| 80 // seq_file gets confused and the next call to read() will return duplicate |
| 81 // entries including the gate VMA again. |
| 82 // |
| 83 // Avoid this by searching for the gate VMA and breaking early. |
| 84 if (ContainsGateVMA(proc_maps, pos)) |
| 85 break; |
| 86 } |
| 87 |
| 88 return true; |
28 } | 89 } |
29 | 90 |
30 bool ParseProcMaps(const std::string& input, | 91 bool ParseProcMaps(const std::string& input, |
31 std::vector<MappedMemoryRegion>* regions_out) { | 92 std::vector<MappedMemoryRegion>* regions_out) { |
32 std::vector<MappedMemoryRegion> regions; | 93 std::vector<MappedMemoryRegion> regions; |
33 | 94 |
34 // This isn't async safe nor terribly efficient, but it doesn't need to be at | 95 // This isn't async safe nor terribly efficient, but it doesn't need to be at |
35 // this point in time. | 96 // this point in time. |
36 std::vector<std::string> lines; | 97 std::vector<std::string> lines; |
37 SplitString(input, '\n', &lines); | 98 SplitString(input, '\n', &lines); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 regions.push_back(region); | 153 regions.push_back(region); |
93 regions.back().path.assign(line + path_index); | 154 regions.back().path.assign(line + path_index); |
94 } | 155 } |
95 | 156 |
96 regions_out->swap(regions); | 157 regions_out->swap(regions); |
97 return true; | 158 return true; |
98 } | 159 } |
99 | 160 |
100 } // namespace debug | 161 } // namespace debug |
101 } // namespace base | 162 } // namespace base |
OLD | NEW |