Chromium Code Reviews| 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]", 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]", pos) != std::string::npos; | |
| 36 #else | |
| 37 // Otherwise assume there is no gate VMA and that we won't hit the kernel bug. | |
| 38 return false; | |
| 39 #endif | |
| 40 } | |
| 41 | |
| 25 bool ReadProcMaps(std::string* proc_maps) { | 42 bool ReadProcMaps(std::string* proc_maps) { |
| 26 FilePath proc_maps_path("/proc/self/maps"); | 43 // There's no point calling read() on procfs with a large buffer as seq_file |
| 27 return file_util::ReadFileToString(proc_maps_path, proc_maps); | 44 // only writes out a page-sized amount of data each call. |
| 45 // | |
| 46 // Unfortunately this means we are unable to atomically read the entire | |
| 47 // contents of /proc/self/maps in a single read(). | |
| 48 const long kBufferSize = sysconf(_SC_PAGESIZE); | |
| 49 scoped_ptr<char[]> buffer(new char[kBufferSize]); | |
| 50 | |
| 51 int fd = HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)); | |
| 52 if (fd == -1) { | |
| 53 DPLOG(ERROR) << "Couldn't open /proc/self/maps"; | |
| 54 return false; | |
| 55 } | |
| 56 file_util::ScopedFD fd_closer(&fd); | |
| 57 | |
| 58 while (true) { | |
| 59 ssize_t bytes_read = HANDLE_EINTR(read(fd, buffer.get(), kBufferSize)); | |
|
Alexander Potapenko
2013/07/15 08:17:19
I wonder what should we do in the case the last li
scherkus (not reviewing)
2013/07/15 17:46:55
seq_file protects against that by only allowing wh
| |
| 60 if (bytes_read < 0) { | |
| 61 DPLOG(ERROR) << "Couldn't read /proc/self/maps"; | |
| 62 return false; | |
| 63 } | |
| 64 | |
| 65 if (bytes_read == 0) | |
| 66 break; | |
| 67 | |
| 68 // Use 2-arg version of append() as |buffer| *is not* NUL-terminated. This | |
| 69 // also avoids an unnecessary length computation. | |
| 70 size_t pos = proc_maps->size(); | |
| 71 proc_maps->append(buffer.get(), bytes_read); | |
| 72 | |
| 73 // Break early if we find the gate VMA. | |
| 74 // | |
| 75 // Otherwise we risk running into a kernel bug where if additional virtual | |
| 76 // memory table entries are added before the next call to read(), we will | |
| 77 // duplicate the last few entries including the gate VMA. | |
| 78 if (ContainsGateVMA(proc_maps, pos)) | |
| 79 break; | |
| 80 } | |
| 81 | |
| 82 return true; | |
| 28 } | 83 } |
| 29 | 84 |
| 30 bool ParseProcMaps(const std::string& input, | 85 bool ParseProcMaps(const std::string& input, |
| 31 std::vector<MappedMemoryRegion>* regions_out) { | 86 std::vector<MappedMemoryRegion>* regions_out) { |
| 32 std::vector<MappedMemoryRegion> regions; | 87 std::vector<MappedMemoryRegion> regions; |
| 33 | 88 |
| 34 // This isn't async safe nor terribly efficient, but it doesn't need to be at | 89 // This isn't async safe nor terribly efficient, but it doesn't need to be at |
| 35 // this point in time. | 90 // this point in time. |
| 36 std::vector<std::string> lines; | 91 std::vector<std::string> lines; |
| 37 SplitString(input, '\n', &lines); | 92 SplitString(input, '\n', &lines); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 92 regions.push_back(region); | 147 regions.push_back(region); |
| 93 regions.back().path.assign(line + path_index); | 148 regions.back().path.assign(line + path_index); |
| 94 } | 149 } |
| 95 | 150 |
| 96 regions_out->swap(regions); | 151 regions_out->swap(regions); |
| 97 return true; | 152 return true; |
| 98 } | 153 } |
| 99 | 154 |
| 100 } // namespace debug | 155 } // namespace debug |
| 101 } // namespace base | 156 } // namespace base |
| OLD | NEW |