blob: c02d96cafc757d2f4ea9b8a3593ac602e0286451 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2013 The Chromium Authors
[email protected]959a8bf2013-07-03 02:02:232// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_
6#define BASE_DEBUG_PROC_MAPS_LINUX_H_
7
aviebe805c2015-12-24 08:20:288#include <stdint.h>
9
Thiabaud Engelbrecht309fb1ea2024-10-29 15:35:1910#include <optional>
[email protected]959a8bf2013-07-03 02:02:2311#include <string>
12#include <vector>
13
14#include "base/base_export.h"
[email protected]959a8bf2013-07-03 02:02:2315
Thiabaud Engelbrecht309fb1ea2024-10-29 15:35:1916namespace base::debug {
[email protected]959a8bf2013-07-03 02:02:2317
18// Describes a region of mapped memory and the path of the file mapped.
Thiabaud Engelbrecht50b1fd72024-10-18 19:53:5319struct BASE_EXPORT MappedMemoryRegion {
[email protected]959a8bf2013-07-03 02:02:2320 enum Permission {
21 READ = 1 << 0,
22 WRITE = 1 << 1,
23 EXECUTE = 1 << 2,
24 PRIVATE = 1 << 3, // If set, region is private, otherwise it is shared.
25 };
26
Thiabaud Engelbrechta383afc2024-10-10 20:59:4927 MappedMemoryRegion();
28 MappedMemoryRegion(const MappedMemoryRegion&);
29 MappedMemoryRegion(MappedMemoryRegion&&);
30
[email protected]959a8bf2013-07-03 02:02:2331 // The address range [start,end) of mapped memory.
32 uintptr_t start;
33 uintptr_t end;
34
35 // Byte offset into |path| of the range mapped into memory.
36 unsigned long long offset;
37
Peter Collingbourne1a3ed312017-11-04 02:37:4738 // Image base, if this mapping corresponds to an ELF image.
39 uintptr_t base;
40
[email protected]959a8bf2013-07-03 02:02:2341 // Bitmask of read/write/execute/private/shared permissions.
aviebe805c2015-12-24 08:20:2842 uint8_t permissions;
[email protected]959a8bf2013-07-03 02:02:2343
Thiabaud Engelbrechta383afc2024-10-10 20:59:4944 uint8_t dev_major;
45 uint8_t dev_minor;
46 long inode;
47
[email protected]959a8bf2013-07-03 02:02:2348 // Name of the file mapped into memory.
49 //
50 // NOTE: path names aren't guaranteed to point at valid files. For example,
51 // "[heap]" and "[stack]" are used to represent the location of the process'
52 // heap and stack, respectively.
53 std::string path;
54};
55
56// Reads the data from /proc/self/maps and stores the result in |proc_maps|.
57// Returns true if successful, false otherwise.
[email protected]35c80832013-09-06 05:07:5058//
59// There is *NO* guarantee that the resulting contents will be free of
60// duplicates or even contain valid entries by time the method returns.
61//
62//
63// THE GORY DETAILS
64//
65// Did you know it's next-to-impossible to atomically read the whole contents
66// of /proc/<pid>/maps? You would think that if we passed in a large-enough
67// buffer to read() that It Should Just Work(tm), but sadly that's not the case.
68//
69// Linux's procfs uses seq_file [1] for handling iteration, text formatting,
70// and dealing with resulting data that is larger than the size of a page. That
71// last bit is especially important because it means that seq_file will never
72// return more than the size of a page in a single call to read().
73//
74// Unfortunately for a program like Chrome the size of /proc/self/maps is
75// larger than the size of page so we're forced to call read() multiple times.
76// If the virtual memory table changed in any way between calls to read() (e.g.,
77// a different thread calling mprotect()), it can make seq_file generate
78// duplicate entries or skip entries.
79//
80// Even if seq_file was changed to keep flushing the contents of its page-sized
81// buffer to the usermode buffer inside a single call to read(), it has to
82// release its lock on the virtual memory table to handle page faults while
83// copying data to usermode. This puts us in the same situation where the table
84// can change while we're copying data.
85//
86// Alternatives such as fork()-and-suspend-the-parent-while-child-reads were
87// attempted, but they present more subtle problems than it's worth. Depending
88// on your use case your best bet may be to read /proc/<pid>/maps prior to
89// starting other threads.
90//
91// [1] http://kernelnewbies.org/Documents/SeqFileHowTo
[email protected]959a8bf2013-07-03 02:02:2392BASE_EXPORT bool ReadProcMaps(std::string* proc_maps);
93
94// Parses /proc/<pid>/maps input data and stores in |regions|. Returns true
95// and updates |regions| if and only if all of |input| was successfully parsed.
96BASE_EXPORT bool ParseProcMaps(const std::string& input,
97 std::vector<MappedMemoryRegion>* regions);
98
Thiabaud Engelbrecht309fb1ea2024-10-29 15:35:1999struct SmapsRollup {
100 size_t rss = 0;
101 size_t pss = 0;
102 size_t pss_anon = 0;
103 size_t pss_file = 0;
104 size_t pss_shmem = 0;
105 size_t private_dirty = 0;
106 size_t swap = 0;
107 size_t swap_pss = 0;
108};
109
110// Attempts to read /proc/self/smaps_rollup. Returns nullopt on error.
111BASE_EXPORT std::optional<SmapsRollup> ReadAndParseSmapsRollup();
112
113// |smaps_rollup| should be the result of reading /proc/*/smaps_rollup.
114BASE_EXPORT std::optional<SmapsRollup> ParseSmapsRollupForTesting(
115 const std::string& smaps_rollup);
116
117} // namespace base::debug
[email protected]959a8bf2013-07-03 02:02:23118
119#endif // BASE_DEBUG_PROC_MAPS_LINUX_H_