https://github.com/thechenli created 
https://github.com/llvm/llvm-project/pull/212666

## Summary

`ProcessElfCore` already parses `NT_FILE`, but its cached `PT_LOAD` 
memory-region entries retain only permissions. As a result, memory-region 
queries cannot report their backing filenames.

- retain the pathname from an exact-matching `NT_FILE` entry alongside each 
cached region permission set
- populate names after all program headers are parsed, making the result 
independent of `PT_LOAD` and `PT_NOTE` ordering
- return the cached name from `DoGetMemoryRegionInfo`, including for 
file-backed mappings with `p_filesz == 0`
- add API coverage for a zero-file-size HSACO-style mapping and ensure the 
adjacent unmapped range remains unnamed

## Testing

- `ninja -C build -j64 lldb yaml2obj lldb-api-test-deps`
- `build/bin/llvm-lit -sv lldb/test/API/functionalities/postmortem/elf-core` 
(4/4 passed)

## Tool assistance

Assisted-by: OpenAI Codex


>From 279d73e3812c0600d276c8cde23b36235eee95ff Mon Sep 17 00:00:00 2001
From: Chen Li <[email protected]>
Date: Tue, 28 Jul 2026 18:48:13 -0700
Subject: [PATCH] [lldb][elf-core] Populate memory region names from NT_FILE

Cache paths from exact-matching NT_FILE entries alongside PT_LOAD permissions. 
This lets memory region queries report backing filenames even when p_filesz is 
zero, without repeatedly scanning the note data.

Add API coverage for a zero-file-size load segment and verify that the adjacent 
unmapped range remains unnamed.

Assisted-by: OpenAI Codex
---
 .../Process/elf-core/ProcessElfCore.cpp       | 48 ++++++++++++++-----
 .../Plugins/Process/elf-core/ProcessElfCore.h | 21 ++++++--
 .../postmortem/elf-core/TestLinuxCore.py      | 35 ++++++++++++++
 .../elf-core/elf-NT_FILE-memory-region.yaml   | 24 ++++++++++
 4 files changed, 111 insertions(+), 17 deletions(-)
 create mode 100644 
lldb/test/API/functionalities/postmortem/elf-core/elf-NT_FILE-memory-region.yaml

diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp 
b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 4cc760de54a5c..aca4133f71e1d 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -8,6 +8,7 @@
 
 #include <cstdlib>
 
+#include <map>
 #include <memory>
 
 #include "lldb/Core/Module.h"
@@ -139,8 +140,8 @@ lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(
       ((header.p_flags & llvm::ELF::PF_W) ? lldb::ePermissionsWritable : 0u) |
       ((header.p_flags & llvm::ELF::PF_X) ? lldb::ePermissionsExecutable : 0u);
 
-  m_core_range_infos.Append(
-      VMRangeToPermissions::Entry(addr, header.p_memsz, permissions));
+  m_core_range_infos.Append(VMRangeToPermissionsAndName::Entry(
+      addr, header.p_memsz, PermissionsAndName{permissions, {}}));
 
   return addr;
 }
@@ -228,6 +229,8 @@ Status ProcessElfCore::DoLoadCore() {
     m_core_tag_ranges.Sort();
   }
 
+  UpdateMemoryRegionNames();
+
   // Ensure we found at least one thread that was stopped on a signal.
   bool siginfo_signal_found = false;
   bool prstatus_signal_found = false;
@@ -316,6 +319,24 @@ void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
   }
 }
 
+void ProcessElfCore::UpdateMemoryRegionNames() {
+  using AddressRange = std::pair<lldb::addr_t, lldb::addr_t>;
+  std::map<AddressRange, const std::string *> nt_file_names;
+  for (const NT_FILE_Entry &file_entry : m_nt_file_entries) {
+    nt_file_names.try_emplace({file_entry.start, file_entry.end},
+                              &file_entry.path);
+  }
+
+  for (size_t i = 0; i < m_core_range_infos.GetSize(); ++i) {
+    VMRangeToPermissionsAndName::Entry *range_entry =
+        m_core_range_infos.GetMutableEntryAtIndex(i);
+    auto name = nt_file_names.find(
+        {range_entry->GetRangeBase(), range_entry->GetRangeEnd()});
+    if (name != nt_file_names.end())
+      range_entry->data.name = *name->second;
+  }
+}
+
 /// Correctly create a FileSpec from a path found in a core file.
 ///
 /// This method will guess the path style more intelligently that specifying
@@ -466,13 +487,13 @@ size_t ProcessElfCore::ReadMemory(lldb::addr_t addr, void 
*buf, size_t size,
 Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
                                              MemoryRegionInfo &region_info) {
   region_info.Clear();
-  const VMRangeToPermissions::Entry *permission_entry =
+  const VMRangeToPermissionsAndName::Entry *range_entry =
       m_core_range_infos.FindEntryThatContainsOrFollows(load_addr);
-  if (permission_entry) {
-    if (permission_entry->Contains(load_addr)) {
-      region_info.GetRange().SetRangeBase(permission_entry->GetRangeBase());
-      region_info.GetRange().SetRangeEnd(permission_entry->GetRangeEnd());
-      const Flags permissions(permission_entry->data);
+  if (range_entry) {
+    if (range_entry->Contains(load_addr)) {
+      region_info.GetRange().SetRangeBase(range_entry->GetRangeBase());
+      region_info.GetRange().SetRangeEnd(range_entry->GetRangeEnd());
+      const Flags permissions(range_entry->data.permissions);
       region_info.SetReadable(permissions.Test(lldb::ePermissionsReadable)
                                   ? eLazyBoolYes
                                   : eLazyBoolNo);
@@ -483,18 +504,19 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t 
load_addr,
                                     ? eLazyBoolYes
                                     : eLazyBoolNo);
       region_info.SetMapped(eLazyBoolYes);
+      if (!range_entry->data.name.empty())
+        region_info.SetName(range_entry->data.name.c_str());
 
       // A region is memory tagged if there is a memory tag segment that covers
       // the exact same range.
       region_info.SetMemoryTagged(eLazyBoolNo);
       const VMRangeToFileOffset::Entry *tag_entry =
-          
m_core_tag_ranges.FindEntryStartsAt(permission_entry->GetRangeBase());
-      if (tag_entry &&
-          tag_entry->GetRangeEnd() == permission_entry->GetRangeEnd())
+          m_core_tag_ranges.FindEntryStartsAt(range_entry->GetRangeBase());
+      if (tag_entry && tag_entry->GetRangeEnd() == range_entry->GetRangeEnd())
         region_info.SetMemoryTagged(eLazyBoolYes);
-    } else if (load_addr < permission_entry->GetRangeBase()) {
+    } else if (load_addr < range_entry->GetRangeBase()) {
       region_info.GetRange().SetRangeBase(load_addr);
-      region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
+      region_info.GetRange().SetRangeEnd(range_entry->GetRangeBase());
       region_info.SetReadable(eLazyBoolNo);
       region_info.SetWritable(eLazyBoolNo);
       region_info.SetExecutable(eLazyBoolNo);
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h 
b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index 846d8cb91cadf..45a89bc6d5b33 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -120,12 +120,22 @@ class ProcessElfCore : public 
lldb_private::PostMortemProcess {
     std::string path;
   };
 
+  struct PermissionsAndName {
+    uint32_t permissions = 0;
+    std::string name;
+
+    bool operator<(const PermissionsAndName &rhs) const {
+      return permissions < rhs.permissions;
+    }
+  };
+
   // For ProcessElfCore only
   typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
   typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange>
       VMRangeToFileOffset;
-  typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t>
-      VMRangeToPermissions;
+  typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t,
+                                        PermissionsAndName>
+      VMRangeToPermissionsAndName;
 
   lldb::ModuleSP m_core_module_sp;
   std::string m_dyld_plugin_name;
@@ -142,8 +152,8 @@ class ProcessElfCore : public 
lldb_private::PostMortemProcess {
   // Address ranges found in the core
   VMRangeToFileOffset m_core_aranges;
 
-  // Permissions for all ranges
-  VMRangeToPermissions m_core_range_infos;
+  // Permissions and names for all ranges
+  VMRangeToPermissionsAndName m_core_range_infos;
 
   // Memory tag ranges found in the core
   VMRangeToFileOffset m_core_tag_ranges;
@@ -170,6 +180,9 @@ class ProcessElfCore : public 
lldb_private::PostMortemProcess {
   // Populate gnu uuid for each NT_FILE entry
   void UpdateBuildIdForNTFileEntries();
 
+  // Populate memory region names from NT_FILE entries.
+  void UpdateMemoryRegionNames();
+
   bool FindModuleUUID(lldb_private::ModuleSpec &spec) override;
 
   // Extract the executable module spec for the executable in this core file.
diff --git a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py 
b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
index f211ac4454209..d4e504096ec3a 100644
--- a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
+++ b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py
@@ -1437,6 +1437,41 @@ def do_test(self, filename, pid, region_count, 
thread_name):
 
         self.dbg.DeleteTarget(target)
 
+    @skipIfLLVMTargetMissing("X86")
+    @skipIfWindows
+    def test_memory_region_name_from_nt_file(self):
+        yaml_path = self.getSourcePath("elf-NT_FILE-memory-region.yaml")
+        core_path = self.getBuildArtifact("elf-NT_FILE-memory-region.core")
+        self.yaml2obj(yaml_path, core_path)
+        target = self.dbg.CreateTarget(None)
+        process = target.LoadCore(core_path)
+        self.assertTrue(process.IsValid())
+
+        region = lldb.SBMemoryRegionInfo()
+        self.assertSuccess(process.GetMemoryRegionInfo(0x400000, region))
+        self.assertEqual(region.GetRegionBase(), 0x400000)
+        self.assertEqual(region.GetRegionEnd(), 0x401000)
+        self.assertTrue(region.IsMapped())
+        self.assertTrue(region.IsReadable())
+        self.assertFalse(region.IsWritable())
+        self.assertTrue(region.IsExecutable())
+        self.assertEqual(region.GetName(), "/tmp/kernel.hsaco")
+
+        regions = process.GetMemoryRegions()
+        self.assertEqual(regions.GetSize(), 1)
+        listed_region = lldb.SBMemoryRegionInfo()
+        self.assertTrue(
+            regions.GetMemoryRegionContainingAddress(0x400000, listed_region)
+        )
+        self.assertEqual(listed_region, region)
+
+        unmapped_region = lldb.SBMemoryRegionInfo()
+        self.assertSuccess(process.GetMemoryRegionInfo(0x401000, 
unmapped_region))
+        self.assertFalse(unmapped_region.IsMapped())
+        self.assertIsNone(unmapped_region.GetName())
+
+        self.dbg.DeleteTarget(target)
+
     @skipIfLLVMTargetMissing("X86")
     @skipIfWindows
     def test_exe_name_extraction_nt_file(self):
diff --git 
a/lldb/test/API/functionalities/postmortem/elf-core/elf-NT_FILE-memory-region.yaml
 
b/lldb/test/API/functionalities/postmortem/elf-core/elf-NT_FILE-memory-region.yaml
new file mode 100644
index 0000000000000..6c61edeb3f8a6
--- /dev/null
+++ 
b/lldb/test/API/functionalities/postmortem/elf-core/elf-NT_FILE-memory-region.yaml
@@ -0,0 +1,24 @@
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_CORE
+  Machine: EM_X86_64
+  OSABI:   ELFOSABI_LINUX
+ProgramHeaders:
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_X ]
+    VAddr:    0x400000
+    Align:    0x1000
+    FileSize: 0
+    MemSize:  0x1000
+  - Type:     PT_NOTE
+    FirstSec: .note
+    LastSec:  .note
+Sections:
+  - Name: .note
+    Type: SHT_NOTE
+    Notes:
+      - Name: CORE
+        Type: NT_FILE
+        Desc: 
010000000000000000100000000000000000400000000000001040000000000000000000000000002f746d702f6b65726e656c2e687361636f00

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to