1026e1bf5SGreg Clayton //===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===// 2026e1bf5SGreg Clayton // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6026e1bf5SGreg Clayton // 7026e1bf5SGreg Clayton //===----------------------------------------------------------------------===// 8026e1bf5SGreg Clayton 9026e1bf5SGreg Clayton #include "LinuxProcMaps.h" 10026e1bf5SGreg Clayton #include "llvm/ADT/StringRef.h" 11026e1bf5SGreg Clayton #include "lldb/Target/MemoryRegionInfo.h" 12026e1bf5SGreg Clayton #include "lldb/Utility/Status.h" 13026e1bf5SGreg Clayton #include "lldb/Utility/StringExtractor.h" 14026e1bf5SGreg Clayton 15026e1bf5SGreg Clayton using namespace lldb_private; 16026e1bf5SGreg Clayton 17026e1bf5SGreg Clayton static Status 18026e1bf5SGreg Clayton ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, 19026e1bf5SGreg Clayton MemoryRegionInfo &memory_region_info) { 20026e1bf5SGreg Clayton memory_region_info.Clear(); 21026e1bf5SGreg Clayton 22026e1bf5SGreg Clayton StringExtractor line_extractor(maps_line); 23026e1bf5SGreg Clayton 24026e1bf5SGreg Clayton // Format: {address_start_hex}-{address_end_hex} perms offset dev inode 25026e1bf5SGreg Clayton // pathname perms: rwxp (letter is present if set, '-' if not, final 26026e1bf5SGreg Clayton // character is p=private, s=shared). 27026e1bf5SGreg Clayton 28026e1bf5SGreg Clayton // Parse out the starting address 29026e1bf5SGreg Clayton lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0); 30026e1bf5SGreg Clayton 31026e1bf5SGreg Clayton // Parse out hyphen separating start and end address from range. 32026e1bf5SGreg Clayton if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-')) 33026e1bf5SGreg Clayton return Status( 34026e1bf5SGreg Clayton "malformed /proc/{pid}/maps entry, missing dash between address range"); 35026e1bf5SGreg Clayton 36026e1bf5SGreg Clayton // Parse out the ending address 37026e1bf5SGreg Clayton lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address); 38026e1bf5SGreg Clayton 39026e1bf5SGreg Clayton // Parse out the space after the address. 40026e1bf5SGreg Clayton if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' ')) 41026e1bf5SGreg Clayton return Status( 42026e1bf5SGreg Clayton "malformed /proc/{pid}/maps entry, missing space after range"); 43026e1bf5SGreg Clayton 44026e1bf5SGreg Clayton // Save the range. 45026e1bf5SGreg Clayton memory_region_info.GetRange().SetRangeBase(start_address); 46026e1bf5SGreg Clayton memory_region_info.GetRange().SetRangeEnd(end_address); 47026e1bf5SGreg Clayton 48026e1bf5SGreg Clayton // Any memory region in /proc/{pid}/maps is by definition mapped into the 49026e1bf5SGreg Clayton // process. 50026e1bf5SGreg Clayton memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); 51026e1bf5SGreg Clayton 52026e1bf5SGreg Clayton // Parse out each permission entry. 53026e1bf5SGreg Clayton if (line_extractor.GetBytesLeft() < 4) 54026e1bf5SGreg Clayton return Status("malformed /proc/{pid}/maps entry, missing some portion of " 55026e1bf5SGreg Clayton "permissions"); 56026e1bf5SGreg Clayton 57026e1bf5SGreg Clayton // Handle read permission. 58026e1bf5SGreg Clayton const char read_perm_char = line_extractor.GetChar(); 59026e1bf5SGreg Clayton if (read_perm_char == 'r') 60026e1bf5SGreg Clayton memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); 61026e1bf5SGreg Clayton else if (read_perm_char == '-') 62026e1bf5SGreg Clayton memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); 63026e1bf5SGreg Clayton else 64026e1bf5SGreg Clayton return Status("unexpected /proc/{pid}/maps read permission char"); 65026e1bf5SGreg Clayton 66026e1bf5SGreg Clayton // Handle write permission. 67026e1bf5SGreg Clayton const char write_perm_char = line_extractor.GetChar(); 68026e1bf5SGreg Clayton if (write_perm_char == 'w') 69026e1bf5SGreg Clayton memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); 70026e1bf5SGreg Clayton else if (write_perm_char == '-') 71026e1bf5SGreg Clayton memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); 72026e1bf5SGreg Clayton else 73026e1bf5SGreg Clayton return Status("unexpected /proc/{pid}/maps write permission char"); 74026e1bf5SGreg Clayton 75026e1bf5SGreg Clayton // Handle execute permission. 76026e1bf5SGreg Clayton const char exec_perm_char = line_extractor.GetChar(); 77026e1bf5SGreg Clayton if (exec_perm_char == 'x') 78026e1bf5SGreg Clayton memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); 79026e1bf5SGreg Clayton else if (exec_perm_char == '-') 80026e1bf5SGreg Clayton memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); 81026e1bf5SGreg Clayton else 82026e1bf5SGreg Clayton return Status("unexpected /proc/{pid}/maps exec permission char"); 83026e1bf5SGreg Clayton 84026e1bf5SGreg Clayton line_extractor.GetChar(); // Read the private bit 85026e1bf5SGreg Clayton line_extractor.SkipSpaces(); // Skip the separator 86026e1bf5SGreg Clayton line_extractor.GetHexMaxU64(false, 0); // Read the offset 87026e1bf5SGreg Clayton line_extractor.GetHexMaxU64(false, 0); // Read the major device number 88026e1bf5SGreg Clayton line_extractor.GetChar(); // Read the device id separator 89026e1bf5SGreg Clayton line_extractor.GetHexMaxU64(false, 0); // Read the major device number 90026e1bf5SGreg Clayton line_extractor.SkipSpaces(); // Skip the separator 91026e1bf5SGreg Clayton line_extractor.GetU64(0, 10); // Read the inode number 92026e1bf5SGreg Clayton 93026e1bf5SGreg Clayton line_extractor.SkipSpaces(); 94026e1bf5SGreg Clayton const char *name = line_extractor.Peek(); 95026e1bf5SGreg Clayton if (name) 96026e1bf5SGreg Clayton memory_region_info.SetName(name); 97026e1bf5SGreg Clayton 98026e1bf5SGreg Clayton return Status(); 99026e1bf5SGreg Clayton } 100026e1bf5SGreg Clayton 101026e1bf5SGreg Clayton void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map, 102026e1bf5SGreg Clayton LinuxMapCallback const &callback) { 103026e1bf5SGreg Clayton llvm::StringRef lines(linux_map); 104026e1bf5SGreg Clayton llvm::StringRef line; 105026e1bf5SGreg Clayton while (!lines.empty()) { 106026e1bf5SGreg Clayton std::tie(line, lines) = lines.split('\n'); 107026e1bf5SGreg Clayton MemoryRegionInfo region; 108026e1bf5SGreg Clayton Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region); 109026e1bf5SGreg Clayton if (!callback(region, error)) 110026e1bf5SGreg Clayton break; 111026e1bf5SGreg Clayton } 112026e1bf5SGreg Clayton } 113