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 #ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_ | 5 #ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_ |
6 #define BASE_DEBUG_PROC_MAPS_LINUX_H_ | 6 #define BASE_DEBUG_PROC_MAPS_LINUX_H_ |
7 | 7 |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 25 matching lines...) Expand all Loading... |
36 // Name of the file mapped into memory. | 36 // Name of the file mapped into memory. |
37 // | 37 // |
38 // NOTE: path names aren't guaranteed to point at valid files. For example, | 38 // NOTE: path names aren't guaranteed to point at valid files. For example, |
39 // "[heap]" and "[stack]" are used to represent the location of the process' | 39 // "[heap]" and "[stack]" are used to represent the location of the process' |
40 // heap and stack, respectively. | 40 // heap and stack, respectively. |
41 std::string path; | 41 std::string path; |
42 }; | 42 }; |
43 | 43 |
44 // Reads the data from /proc/self/maps and stores the result in |proc_maps|. | 44 // Reads the data from /proc/self/maps and stores the result in |proc_maps|. |
45 // Returns true if successful, false otherwise. | 45 // Returns true if successful, false otherwise. |
| 46 // |
| 47 // There is *NO* guarantee that the resulting contents will be free of |
| 48 // duplicates or even contain valid entries by time the method returns. |
| 49 // |
| 50 // |
| 51 // THE GORY DETAILS |
| 52 // |
| 53 // Did you know it's next-to-impossible to atomically read the whole contents |
| 54 // of /proc/<pid>/maps? You would think that if we passed in a large-enough |
| 55 // buffer to read() that It Should Just Work(tm), but sadly that's not the case. |
| 56 // |
| 57 // Linux's procfs uses seq_file [1] for handling iteration, text formatting, |
| 58 // and dealing with resulting data that is larger than the size of a page. That |
| 59 // last bit is especially important because it means that seq_file will never |
| 60 // return more than the size of a page in a single call to read(). |
| 61 // |
| 62 // Unfortunately for a program like Chrome the size of /proc/self/maps is |
| 63 // larger than the size of page so we're forced to call read() multiple times. |
| 64 // If the virtual memory table changed in any way between calls to read() (e.g., |
| 65 // a different thread calling mprotect()), it can make seq_file generate |
| 66 // duplicate entries or skip entries. |
| 67 // |
| 68 // Even if seq_file was changed to keep flushing the contents of its page-sized |
| 69 // buffer to the usermode buffer inside a single call to read(), it has to |
| 70 // release its lock on the virtual memory table to handle page faults while |
| 71 // copying data to usermode. This puts us in the same situation where the table |
| 72 // can change while we're copying data. |
| 73 // |
| 74 // Alternatives such as fork()-and-suspend-the-parent-while-child-reads were |
| 75 // attempted, but they present more subtle problems than it's worth. Depending |
| 76 // on your use case your best bet may be to read /proc/<pid>/maps prior to |
| 77 // starting other threads. |
| 78 // |
| 79 // [1] http://kernelnewbies.org/Documents/SeqFileHowTo |
46 BASE_EXPORT bool ReadProcMaps(std::string* proc_maps); | 80 BASE_EXPORT bool ReadProcMaps(std::string* proc_maps); |
47 | 81 |
48 // Parses /proc/<pid>/maps input data and stores in |regions|. Returns true | 82 // Parses /proc/<pid>/maps input data and stores in |regions|. Returns true |
49 // and updates |regions| if and only if all of |input| was successfully parsed. | 83 // and updates |regions| if and only if all of |input| was successfully parsed. |
50 BASE_EXPORT bool ParseProcMaps(const std::string& input, | 84 BASE_EXPORT bool ParseProcMaps(const std::string& input, |
51 std::vector<MappedMemoryRegion>* regions); | 85 std::vector<MappedMemoryRegion>* regions); |
52 | 86 |
53 } // namespace debug | 87 } // namespace debug |
54 } // namespace base | 88 } // namespace base |
55 | 89 |
56 #endif // BASE_DEBUG_PROC_MAPS_LINUX_H_ | 90 #endif // BASE_DEBUG_PROC_MAPS_LINUX_H_ |
OLD | NEW |