1 //===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "LinuxProcMaps.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "lldb/Target/MemoryRegionInfo.h"
12 #include "lldb/Utility/Status.h"
13 #include "lldb/Utility/StringExtractor.h"
15 using namespace lldb_private;
18 ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
19 MemoryRegionInfo &memory_region_info) {
20 memory_region_info.Clear();
22 StringExtractor line_extractor(maps_line);
24 // Format: {address_start_hex}-{address_end_hex} perms offset dev inode
25 // pathname perms: rwxp (letter is present if set, '-' if not, final
26 // character is p=private, s=shared).
28 // Parse out the starting address
29 lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0);
31 // Parse out hyphen separating start and end address from range.
32 if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-'))
34 "malformed /proc/{pid}/maps entry, missing dash between address range");
36 // Parse out the ending address
37 lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address);
39 // Parse out the space after the address.
40 if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' '))
42 "malformed /proc/{pid}/maps entry, missing space after range");
45 memory_region_info.GetRange().SetRangeBase(start_address);
46 memory_region_info.GetRange().SetRangeEnd(end_address);
48 // Any memory region in /proc/{pid}/maps is by definition mapped into the
50 memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
52 // Parse out each permission entry.
53 if (line_extractor.GetBytesLeft() < 4)
54 return Status("malformed /proc/{pid}/maps entry, missing some portion of "
57 // Handle read permission.
58 const char read_perm_char = line_extractor.GetChar();
59 if (read_perm_char == 'r')
60 memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
61 else if (read_perm_char == '-')
62 memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
64 return Status("unexpected /proc/{pid}/maps read permission char");
66 // Handle write permission.
67 const char write_perm_char = line_extractor.GetChar();
68 if (write_perm_char == 'w')
69 memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
70 else if (write_perm_char == '-')
71 memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
73 return Status("unexpected /proc/{pid}/maps write permission char");
75 // Handle execute permission.
76 const char exec_perm_char = line_extractor.GetChar();
77 if (exec_perm_char == 'x')
78 memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
79 else if (exec_perm_char == '-')
80 memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
82 return Status("unexpected /proc/{pid}/maps exec permission char");
84 line_extractor.GetChar(); // Read the private bit
85 line_extractor.SkipSpaces(); // Skip the separator
86 line_extractor.GetHexMaxU64(false, 0); // Read the offset
87 line_extractor.GetHexMaxU64(false, 0); // Read the major device number
88 line_extractor.GetChar(); // Read the device id separator
89 line_extractor.GetHexMaxU64(false, 0); // Read the major device number
90 line_extractor.SkipSpaces(); // Skip the separator
91 line_extractor.GetU64(0, 10); // Read the inode number
93 line_extractor.SkipSpaces();
94 const char *name = line_extractor.Peek();
96 memory_region_info.SetName(name);
101 void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
102 LinuxMapCallback const &callback) {
103 llvm::StringRef lines(linux_map);
104 llvm::StringRef line;
105 while (!lines.empty()) {
106 std::tie(line, lines) = lines.split('\n');
107 MemoryRegionInfo region;
108 Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region);
109 if (!callback(region, error))