Chromium Code Reviews| Index: base/debug/proc_maps_linux.cc |
| diff --git a/base/debug/proc_maps_linux.cc b/base/debug/proc_maps_linux.cc |
| index c9afd45037b7cce2787b5ccc5bdf4d9ed35e3679..014924782d574f6837f70c3de560e28bc85951ed 100644 |
| --- a/base/debug/proc_maps_linux.cc |
| +++ b/base/debug/proc_maps_linux.cc |
| @@ -4,6 +4,8 @@ |
| #include "base/debug/proc_maps_linux.h" |
| +#include <fcntl.h> |
| + |
| #if defined(OS_LINUX) |
| #include <inttypes.h> |
| #endif |
| @@ -22,9 +24,68 @@ |
| namespace base { |
| namespace debug { |
| +// Scans |proc_maps| starting from |pos| returning true if the gate VMA was |
| +// found, otherwise returns false. |
| +static bool ContainsGateVMA(std::string* proc_maps, size_t pos) { |
| +#if defined(ARCH_CPU_ARM_FAMILY) |
| + // The gate VMA on ARM kernels is the interrupt vectors page. |
| + return proc_maps->find(" [vectors]\n", pos) != std::string::npos; |
| +#elif defined(ARCH_CPU_X86_64) |
| + // The gate VMA on x86 64-bit kernels is the virtual system call page. |
| + return proc_maps->find(" [vsyscall]\n", pos) != std::string::npos; |
| +#else |
| + // Otherwise assume there is no gate VMA in which case we shouldn't |
| + // get duplicate entires. |
| + return false; |
| +#endif |
| +} |
| + |
| bool ReadProcMaps(std::string* proc_maps) { |
| - FilePath proc_maps_path("/proc/self/maps"); |
| - return ReadFileToString(proc_maps_path, proc_maps); |
| + // seq_file only writes out a page-sized amount on each call. Refer to header |
| + // file for details. |
| + const long kReadSize = sysconf(_SC_PAGESIZE); |
| + |
| + int fd = HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)); |
| + if (fd == -1) { |
| + DPLOG(ERROR) << "Couldn't open /proc/self/maps"; |
| + return false; |
| + } |
| + file_util::ScopedFD fd_closer(&fd); |
| + proc_maps->clear(); |
| + |
| + while (true) { |
| + // To avoid a copy, resize |proc_maps| so read() can write directly into it. |
| + // Compute |buffer| afterwards since resize() may reallocate. |
| + size_t pos = proc_maps->size(); |
| + proc_maps->resize(pos + kReadSize); |
| + void* buffer = &proc_maps->front() + pos; |
|
Mark Mentovai
2013/09/05 19:25:50
Simplify to &proc_maps[pos]?
scherkus (not reviewing)
2013/09/05 19:54:51
Done, but tweaked a bit as proc_maps is a pointer
|
| + |
| + ssize_t bytes_read = HANDLE_EINTR(read(fd, buffer, kReadSize)); |
| + if (bytes_read < 0) { |
| + DPLOG(ERROR) << "Couldn't read /proc/self/maps"; |
| + proc_maps->resize(pos); |
|
scherkus (not reviewing)
2013/09/05 19:01:40
I don't know if this is worth it.
Mark Mentovai
2013/09/05 19:25:50
scherkus wrote:
scherkus (not reviewing)
2013/09/05 19:54:51
I like clear().
|
| + return false; |
| + } |
| + |
| + // ... and don't forget to trim off excess bytes. |
| + proc_maps->resize(pos + bytes_read); |
| + |
| + if (bytes_read == 0) |
| + break; |
| + |
| + // The gate VMA is handled as a special case after seq_file has finished |
| + // iterating through all entries in the virtual memory table. |
| + // |
| + // Unfortunately, if additional entries are added at this point in time |
| + // seq_file gets confused and the next call to read() will return duplicate |
| + // entries including the gate VMA again. |
| + // |
| + // Avoid this by searching for the gate VMA and breaking early. |
| + if (ContainsGateVMA(proc_maps, pos)) |
| + break; |
| + } |
| + |
| + return true; |
| } |
| bool ParseProcMaps(const std::string& input, |