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