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