| //===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "LinuxProcMaps.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "lldb/Target/MemoryRegionInfo.h" |
| #include "lldb/Utility/Status.h" |
| #include "lldb/Utility/StringExtractor.h" |
| |
| using namespace lldb_private; |
| |
| static Status |
| ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, |
| MemoryRegionInfo &memory_region_info) { |
| memory_region_info.Clear(); |
| |
| StringExtractor line_extractor(maps_line); |
| |
| // Format: {address_start_hex}-{address_end_hex} perms offset dev inode |
| // pathname perms: rwxp (letter is present if set, '-' if not, final |
| // character is p=private, s=shared). |
| |
| // Parse out the starting address |
| lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0); |
| |
| // Parse out hyphen separating start and end address from range. |
| if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-')) |
| return Status( |
| "malformed /proc/{pid}/maps entry, missing dash between address range"); |
| |
| // Parse out the ending address |
| lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address); |
| |
| // Parse out the space after the address. |
| if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' ')) |
| return Status( |
| "malformed /proc/{pid}/maps entry, missing space after range"); |
| |
| // Save the range. |
| memory_region_info.GetRange().SetRangeBase(start_address); |
| memory_region_info.GetRange().SetRangeEnd(end_address); |
| |
| // Any memory region in /proc/{pid}/maps is by definition mapped into the |
| // process. |
| memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); |
| |
| // Parse out each permission entry. |
| if (line_extractor.GetBytesLeft() < 4) |
| return Status("malformed /proc/{pid}/maps entry, missing some portion of " |
| "permissions"); |
| |
| // Handle read permission. |
| const char read_perm_char = line_extractor.GetChar(); |
| if (read_perm_char == 'r') |
| memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); |
| else if (read_perm_char == '-') |
| memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); |
| else |
| return Status("unexpected /proc/{pid}/maps read permission char"); |
| |
| // Handle write permission. |
| const char write_perm_char = line_extractor.GetChar(); |
| if (write_perm_char == 'w') |
| memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); |
| else if (write_perm_char == '-') |
| memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); |
| else |
| return Status("unexpected /proc/{pid}/maps write permission char"); |
| |
| // Handle execute permission. |
| const char exec_perm_char = line_extractor.GetChar(); |
| if (exec_perm_char == 'x') |
| memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); |
| else if (exec_perm_char == '-') |
| memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); |
| else |
| return Status("unexpected /proc/{pid}/maps exec permission char"); |
| |
| line_extractor.GetChar(); // Read the private bit |
| line_extractor.SkipSpaces(); // Skip the separator |
| line_extractor.GetHexMaxU64(false, 0); // Read the offset |
| line_extractor.GetHexMaxU64(false, 0); // Read the major device number |
| line_extractor.GetChar(); // Read the device id separator |
| line_extractor.GetHexMaxU64(false, 0); // Read the major device number |
| line_extractor.SkipSpaces(); // Skip the separator |
| line_extractor.GetU64(0, 10); // Read the inode number |
| |
| line_extractor.SkipSpaces(); |
| const char *name = line_extractor.Peek(); |
| if (name) |
| memory_region_info.SetName(name); |
| |
| return Status(); |
| } |
| |
| void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map, |
| LinuxMapCallback const &callback) { |
| llvm::StringRef lines(linux_map); |
| llvm::StringRef line; |
| while (!lines.empty()) { |
| std::tie(line, lines) = lines.split('\n'); |
| MemoryRegionInfo region; |
| Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region); |
| if (!callback(region, error)) |
| break; |
| } |
| } |