LLDB  mainline
LinuxProcMaps.cpp
Go to the documentation of this file.
1 //===-- LinuxProcMaps.cpp -------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "LinuxProcMaps.h"
11 #include "lldb/Utility/Status.h"
13 #include "llvm/ADT/StringRef.h"
14 
15 using namespace lldb_private;
16 
17 enum class MapsKind { Maps, SMaps };
18 
19 static llvm::Expected<MemoryRegionInfo> ProcMapError(const char *msg,
20  MapsKind kind) {
21  return llvm::createStringError(llvm::inconvertibleErrorCode(), msg,
22  kind == MapsKind::Maps ? "maps" : "smaps");
23 }
24 
25 static llvm::Expected<MemoryRegionInfo>
26 ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
27  MapsKind maps_kind) {
28  MemoryRegionInfo region;
29  StringExtractor line_extractor(maps_line);
30 
31  // Format: {address_start_hex}-{address_end_hex} perms offset dev inode
32  // pathname perms: rwxp (letter is present if set, '-' if not, final
33  // character is p=private, s=shared).
34 
35  // Parse out the starting address
36  lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0);
37 
38  // Parse out hyphen separating start and end address from range.
39  if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-'))
40  return ProcMapError(
41  "malformed /proc/{pid}/%s entry, missing dash between address range",
42  maps_kind);
43 
44  // Parse out the ending address
45  lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address);
46 
47  // Parse out the space after the address.
48  if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' '))
49  return ProcMapError(
50  "malformed /proc/{pid}/%s entry, missing space after range", maps_kind);
51 
52  // Save the range.
53  region.GetRange().SetRangeBase(start_address);
54  region.GetRange().SetRangeEnd(end_address);
55 
56  // Any memory region in /proc/{pid}/(maps|smaps) is by definition mapped
57  // into the process.
58  region.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
59 
60  // Parse out each permission entry.
61  if (line_extractor.GetBytesLeft() < 4)
62  return ProcMapError(
63  "malformed /proc/{pid}/%s entry, missing some portion of "
64  "permissions",
65  maps_kind);
66 
67  // Handle read permission.
68  const char read_perm_char = line_extractor.GetChar();
69  if (read_perm_char == 'r')
70  region.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
71  else if (read_perm_char == '-')
72  region.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
73  else
74  return ProcMapError("unexpected /proc/{pid}/%s read permission char",
75  maps_kind);
76 
77  // Handle write permission.
78  const char write_perm_char = line_extractor.GetChar();
79  if (write_perm_char == 'w')
80  region.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
81  else if (write_perm_char == '-')
82  region.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
83  else
84  return ProcMapError("unexpected /proc/{pid}/%s write permission char",
85  maps_kind);
86 
87  // Handle execute permission.
88  const char exec_perm_char = line_extractor.GetChar();
89  if (exec_perm_char == 'x')
90  region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
91  else if (exec_perm_char == '-')
92  region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
93  else
94  return ProcMapError("unexpected /proc/{pid}/%s exec permission char",
95  maps_kind);
96 
97  // Handle sharing status (private/shared).
98  const char sharing_char = line_extractor.GetChar();
99  if (sharing_char == 's')
100  region.SetShared(MemoryRegionInfo::OptionalBool::eYes);
101  else if (sharing_char == 'p')
102  region.SetShared(MemoryRegionInfo::OptionalBool::eNo);
103  else
104  region.SetShared(MemoryRegionInfo::OptionalBool::eDontKnow);
105 
106  line_extractor.SkipSpaces(); // Skip the separator
107  line_extractor.GetHexMaxU64(false, 0); // Read the offset
108  line_extractor.GetHexMaxU64(false, 0); // Read the major device number
109  line_extractor.GetChar(); // Read the device id separator
110  line_extractor.GetHexMaxU64(false, 0); // Read the major device number
111  line_extractor.SkipSpaces(); // Skip the separator
112  line_extractor.GetU64(0, 10); // Read the inode number
113 
114  line_extractor.SkipSpaces();
115  const char *name = line_extractor.Peek();
116  if (name)
117  region.SetName(name);
118 
119  return region;
120 }
121 
122 void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
123  LinuxMapCallback const &callback) {
124  llvm::StringRef lines(linux_map);
125  llvm::StringRef line;
126  while (!lines.empty()) {
127  std::tie(line, lines) = lines.split('\n');
129  break;
130  }
131 }
132 
133 void lldb_private::ParseLinuxSMapRegions(llvm::StringRef linux_smap,
134  LinuxMapCallback const &callback) {
135  // Entries in /smaps look like:
136  // 00400000-0048a000 r-xp 00000000 fd:03 960637
137  // Size: 552 kB
138  // Rss: 460 kB
139  // <...>
140  // VmFlags: rd ex mr mw me dw
141  // 00500000-0058a000 rwxp 00000000 fd:03 960637
142  // <...>
143  //
144  // Where the first line is identical to the /maps format
145  // and VmFlags is only printed for kernels >= 3.8.
146 
147  llvm::StringRef lines(linux_smap);
148  llvm::StringRef line;
149  llvm::Optional<MemoryRegionInfo> region;
150 
151  while (lines.size()) {
152  std::tie(line, lines) = lines.split('\n');
153 
154  // A property line looks like:
155  // <word>: <value>
156  // (no spaces on the left hand side)
157  // A header will have a ':' but the LHS will contain spaces
158  llvm::StringRef name;
159  llvm::StringRef value;
160  std::tie(name, value) = line.split(':');
161 
162  // If this line is a property line
163  if (!name.contains(' ')) {
164  if (region) {
165  if (name == "VmFlags") {
166  if (value.contains("mt"))
167  region->SetMemoryTagged(MemoryRegionInfo::eYes);
168  else
169  region->SetMemoryTagged(MemoryRegionInfo::eNo);
170  }
171  // Ignore anything else
172  } else {
173  // Orphaned settings line
174  callback(ProcMapError(
175  "Found a property line without a corresponding mapping "
176  "in /proc/{pid}/%s",
177  MapsKind::SMaps));
178  return;
179  }
180  } else {
181  // Must be a new region header
182  if (region) {
183  // Save current region
184  callback(*region);
185  region.reset();
186  }
187 
188  // Try to start a new region
189  llvm::Expected<MemoryRegionInfo> new_region =
191  if (new_region) {
192  region = *new_region;
193  } else {
194  // Stop at first invalid region header
195  callback(new_region.takeError());
196  return;
197  }
198  }
199  }
200 
201  // Catch last region
202  if (region)
203  callback(*region);
204 }
ProcMapError
static llvm::Expected< MemoryRegionInfo > ProcMapError(const char *msg, MapsKind kind)
Definition: LinuxProcMaps.cpp:19
MapsKind::Maps
@ Maps
StringExtractor::GetBytesLeft
size_t GetBytesLeft()
Definition: StringExtractor.h:52
lldb_private::MemoryRegionInfo::SetName
void SetName(const char *name)
Definition: MemoryRegionInfo.h:68
StringExtractor::SkipSpaces
void SkipSpaces()
Definition: StringExtractor.cpp:365
lldb_private::ParseLinuxMapRegions
void ParseLinuxMapRegions(llvm::StringRef linux_map, LinuxMapCallback const &callback)
Definition: LinuxProcMaps.cpp:122
MapsKind
MapsKind
Definition: LinuxProcMaps.cpp:17
lldb_private::MemoryRegionInfo
Definition: MemoryRegionInfo.h:21
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
lldb_private::MemoryRegionInfo::SetReadable
void SetReadable(OptionalBool val)
Definition: MemoryRegionInfo.h:58
StringExtractor
Definition: StringExtractor.h:19
lldb_private::LinuxMapCallback
std::function< bool(llvm::Expected< MemoryRegionInfo >)> LinuxMapCallback
Definition: LinuxProcMaps.h:18
lldb_private::ParseLinuxSMapRegions
void ParseLinuxSMapRegions(llvm::StringRef linux_smap, LinuxMapCallback const &callback)
Definition: LinuxProcMaps.cpp:133
lldb_private::Range::SetRangeEnd
void SetRangeEnd(BaseType end)
Definition: RangeMap.h:75
StringExtractor::Peek
const char * Peek()
Definition: StringExtractor.h:100
MemoryRegionInfo.h
lldb_private::MemoryRegionInfo::SetExecutable
void SetExecutable(OptionalBool val)
Definition: MemoryRegionInfo.h:62
lldb_private::MemoryRegionInfo::eYes
@ eYes
Definition: MemoryRegionInfo.h:25
StringExtractor::GetChar
char GetChar(char fail_value='\0')
Definition: StringExtractor.cpp:43
lldb_private::MemoryRegionInfo::eNo
@ eNo
Definition: MemoryRegionInfo.h:25
lldb_private::MemoryRegionInfo::SetWritable
void SetWritable(OptionalBool val)
Definition: MemoryRegionInfo.h:60
StringExtractor::GetU64
uint64_t GetU64(uint64_t fail_value, int base=0)
Definition: StringExtractor.cpp:123
StringExtractor::GetHexMaxU64
uint64_t GetHexMaxU64(bool little_endian, uint64_t fail_value)
Definition: StringExtractor.cpp:204
StringExtractor.h
lldb_private::MemoryRegionInfo::SetMapped
void SetMapped(OptionalBool val)
Definition: MemoryRegionInfo.h:66
lldb_private::Range::SetRangeBase
void SetRangeBase(BaseType b)
Definition: RangeMap.h:48
ParseMemoryRegionInfoFromProcMapsLine
static llvm::Expected< MemoryRegionInfo > ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, MapsKind maps_kind)
Definition: LinuxProcMaps.cpp:26
lldb_private::MemoryRegionInfo::GetRange
RangeType & GetRange()
Definition: MemoryRegionInfo.h:38
Status.h
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
LinuxProcMaps.h
MapsKind::SMaps
@ SMaps
lldb_private::MemoryRegionInfo::SetShared
void SetShared(OptionalBool val)
Definition: MemoryRegionInfo.h:64