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