1 //===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 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" 14 15 using namespace lldb_private; 16 17 static Status 18 ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, 19 MemoryRegionInfo &memory_region_info) { 20 memory_region_info.Clear(); 21 22 StringExtractor line_extractor(maps_line); 23 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). 27 28 // Parse out the starting address 29 lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0); 30 31 // Parse out hyphen separating start and end address from range. 32 if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-')) 33 return Status( 34 "malformed /proc/{pid}/maps entry, missing dash between address range"); 35 36 // Parse out the ending address 37 lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address); 38 39 // Parse out the space after the address. 40 if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' ')) 41 return Status( 42 "malformed /proc/{pid}/maps entry, missing space after range"); 43 44 // Save the range. 45 memory_region_info.GetRange().SetRangeBase(start_address); 46 memory_region_info.GetRange().SetRangeEnd(end_address); 47 48 // Any memory region in /proc/{pid}/maps is by definition mapped into the 49 // process. 50 memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); 51 52 // Parse out each permission entry. 53 if (line_extractor.GetBytesLeft() < 4) 54 return Status("malformed /proc/{pid}/maps entry, missing some portion of " 55 "permissions"); 56 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); 63 else 64 return Status("unexpected /proc/{pid}/maps read permission char"); 65 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); 72 else 73 return Status("unexpected /proc/{pid}/maps write permission char"); 74 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); 81 else 82 return Status("unexpected /proc/{pid}/maps exec permission char"); 83 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 92 93 line_extractor.SkipSpaces(); 94 const char *name = line_extractor.Peek(); 95 if (name) 96 memory_region_info.SetName(name); 97 98 return Status(); 99 } 100 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)) 110 break; 111 } 112 } 113