1 //===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "LinuxProcMaps.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "lldb/Target/MemoryRegionInfo.h"
13 #include "lldb/Utility/Status.h"
14 #include "lldb/Utility/StringExtractor.h"
15
16 using namespace lldb_private;
17
18 static Status
ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,MemoryRegionInfo & memory_region_info)19 ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
20 MemoryRegionInfo &memory_region_info) {
21 memory_region_info.Clear();
22
23 StringExtractor line_extractor(maps_line);
24
25 // Format: {address_start_hex}-{address_end_hex} perms offset dev inode
26 // pathname perms: rwxp (letter is present if set, '-' if not, final
27 // character is p=private, s=shared).
28
29 // Parse out the starting address
30 lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0);
31
32 // Parse out hyphen separating start and end address from range.
33 if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-'))
34 return Status(
35 "malformed /proc/{pid}/maps entry, missing dash between address range");
36
37 // Parse out the ending address
38 lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address);
39
40 // Parse out the space after the address.
41 if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' '))
42 return Status(
43 "malformed /proc/{pid}/maps entry, missing space after range");
44
45 // Save the range.
46 memory_region_info.GetRange().SetRangeBase(start_address);
47 memory_region_info.GetRange().SetRangeEnd(end_address);
48
49 // Any memory region in /proc/{pid}/maps is by definition mapped into the
50 // process.
51 memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
52
53 // Parse out each permission entry.
54 if (line_extractor.GetBytesLeft() < 4)
55 return Status("malformed /proc/{pid}/maps entry, missing some portion of "
56 "permissions");
57
58 // Handle read permission.
59 const char read_perm_char = line_extractor.GetChar();
60 if (read_perm_char == 'r')
61 memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
62 else if (read_perm_char == '-')
63 memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
64 else
65 return Status("unexpected /proc/{pid}/maps read permission char");
66
67 // Handle write permission.
68 const char write_perm_char = line_extractor.GetChar();
69 if (write_perm_char == 'w')
70 memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
71 else if (write_perm_char == '-')
72 memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
73 else
74 return Status("unexpected /proc/{pid}/maps write permission char");
75
76 // Handle execute permission.
77 const char exec_perm_char = line_extractor.GetChar();
78 if (exec_perm_char == 'x')
79 memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
80 else if (exec_perm_char == '-')
81 memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
82 else
83 return Status("unexpected /proc/{pid}/maps exec permission char");
84
85 line_extractor.GetChar(); // Read the private bit
86 line_extractor.SkipSpaces(); // Skip the separator
87 line_extractor.GetHexMaxU64(false, 0); // Read the offset
88 line_extractor.GetHexMaxU64(false, 0); // Read the major device number
89 line_extractor.GetChar(); // Read the device id separator
90 line_extractor.GetHexMaxU64(false, 0); // Read the major device number
91 line_extractor.SkipSpaces(); // Skip the separator
92 line_extractor.GetU64(0, 10); // Read the inode number
93
94 line_extractor.SkipSpaces();
95 const char *name = line_extractor.Peek();
96 if (name)
97 memory_region_info.SetName(name);
98
99 return Status();
100 }
101
ParseLinuxMapRegions(llvm::StringRef linux_map,LinuxMapCallback const & callback)102 void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
103 LinuxMapCallback const &callback) {
104 llvm::StringRef lines(linux_map);
105 llvm::StringRef line;
106 while (!lines.empty()) {
107 std::tie(line, lines) = lines.split('\n');
108 MemoryRegionInfo region;
109 Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region);
110 if (!callback(region, error))
111 break;
112 }
113 }
114