Skip to content

Conversation

@GeorgeHuyubo
Copy link
Contributor

This change improves how LLDB's ProcessElfCore plugin identifies the main executable when loading ELF core files. Previously, the code would simply use the first entry in the NT_FILE section, which is not guaranteed to be the main executable, also the first entry might not have a valid UUID.

  1. Storing executable name: Extract the executable name from the ELF NT_PRPSINFO note and store it in m_executable_name

  2. Preferential matching: When selecting the main executable from NT_FILE entries, prefer entries whose path ends with the stored executable name

  3. UUID-based lookup: Call FindModuleUUID() helper function to properly match modules by path and retrieve a valid UUID

@GeorgeHuyubo GeorgeHuyubo marked this pull request as ready for review September 5, 2025 20:41
@llvmbot llvmbot added the lldb label Sep 5, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 5, 2025

@llvm/pr-subscribers-clang-format

@llvm/pr-subscribers-lldb

Author: None (GeorgeHuyubo)

Changes

This change improves how LLDB's ProcessElfCore plugin identifies the main executable when loading ELF core files. Previously, the code would simply use the first entry in the NT_FILE section, which is not guaranteed to be the main executable, also the first entry might not have a valid UUID.

  1. Storing executable name: Extract the executable name from the ELF NT_PRPSINFO note and store it in m_executable_name

  2. Preferential matching: When selecting the main executable from NT_FILE entries, prefer entries whose path ends with the stored executable name

  3. UUID-based lookup: Call FindModuleUUID() helper function to properly match modules by path and retrieve a valid UUID


Full diff: https://github.com/llvm/llvm-project/pull/157170.diff

2 Files Affected:

  • (modified) lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp (+13-3)
  • (modified) lldb/source/Plugins/Process/elf-core/ProcessElfCore.h (+3)
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 88eeddf178788..e88daebebfa7e 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -257,12 +257,21 @@ Status ProcessElfCore::DoLoadCore() {
   // the main executable using data we found in the core file notes.
   lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
   if (!exe_module_sp) {
-    // The first entry in the NT_FILE might be our executable
     if (!m_nt_file_entries.empty()) {
+      // The first entry in the NT_FILE might be our executable
+      llvm::StringRef executable_path = m_nt_file_entries[0].path;
+      // Prefer the NT_FILE entry matching m_executable_name as main executable.
+      for (const NT_FILE_Entry &file_entry : m_nt_file_entries)
+        if (llvm::StringRef(file_entry.path)
+                .ends_with("/" + m_executable_name)) {
+          executable_path = file_entry.path;
+          break;
+        }
+
       ModuleSpec exe_module_spec;
       exe_module_spec.GetArchitecture() = arch;
-      exe_module_spec.GetUUID() = m_nt_file_entries[0].uuid;
-      exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path,
+      exe_module_spec.GetUUID() = FindModuleUUID(executable_path);
+      exe_module_spec.GetFileSpec().SetFile(executable_path,
                                             FileSpec::Style::native);
       if (exe_module_spec.GetFileSpec()) {
         exe_module_sp =
@@ -935,6 +944,7 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) {
         return status.ToError();
       thread_data.name.assign (prpsinfo.pr_fname, strnlen (prpsinfo.pr_fname, sizeof (prpsinfo.pr_fname)));
       SetID(prpsinfo.pr_pid);
+      m_executable_name = prpsinfo.pr_fname;
       break;
     }
     case ELF::NT_SIGINFO: {
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index a91c04a277f60..601c8c4ed1b92 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -152,6 +152,9 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
   // NT_FILE entries found from the NOTE segment
   std::vector<NT_FILE_Entry> m_nt_file_entries;
 
+  // Executable name found from the ELF PRPSINFO
+  std::string m_executable_name;
+
   // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
   llvm::Error ParseThreadContextsFromNoteSegment(
       const elf::ELFProgramHeader &segment_header,

@dmpots dmpots self-requested a review September 9, 2025 17:19
@github-actions

This comment was marked as outdated.

Copy link
Contributor

@dmpots dmpots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get a test case for this?

@GeorgeHuyubo GeorgeHuyubo force-pushed the uuid-bug branch 3 times, most recently from f778f24 to e3de722 Compare September 10, 2025 21:55
@GeorgeHuyubo
Copy link
Contributor Author

Can we get a test case for this?

@dmpots I think this file historically lack a good way of testing changes due to difficulties in hand craft a ELF core file using YAML. The ELF support yaml2obj doesn't allow content to be supplied for a program header. It expects section headers to contain data and ELF core files don't have section headers. So it would take some modifications to the ELF obj2yaml and yaml2obj to support this. It would be great if we can add this support at some point if anyone has expertise in the yaml layer as it would be easy to create a core file, reduce it using a different tool, and then obj2yaml it for a test.

@GeorgeHuyubo GeorgeHuyubo requested a review from dmpots September 10, 2025 22:01
@dmpots
Copy link
Contributor

dmpots commented Sep 10, 2025

Can we get a test case for this?

I think this file historically lack a good way of testing changes due to difficulties in hand craft a ELF core file using YAML.

I see, thanks for the context. Sounds like something we need to fix, but beyond the scope of this PR.

Copy link
Contributor

@dmpots dmpots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@GeorgeHuyubo GeorgeHuyubo merged commit c087da4 into llvm:main Sep 10, 2025
9 checks passed
DavidSpickett added a commit to DavidSpickett/llvm-project that referenced this pull request Sep 17, 2025
llvm#157170 added code that
assigned pr_fname to another std::string member.

In the lines before, we copy pr_fname using assign with a max
length set to either the length of the string in pr_fname, or
the size of pr_fname. Which is 16 bytes.

struct ELFLinuxPrPsInfo {
<...>
  char pr_fname[16];

The content of pr_fname can fill all 16 bytes, that's why
we need the limit.

This was not done for m_executable_name where it ended up
calling the assignment from char* operator which could
read on into the rest of the corefile in some cases.

Likely wouldn't crash for reading out of bounds, but you
would at least see some strange things in LLDB.

Fix this by copying the std::string we already made for
thread_data.name.
DavidSpickett added a commit to DavidSpickett/llvm-project that referenced this pull request Sep 17, 2025
Since llvm#157170 this test has been flakey on several LLDB buildbots.
I suspect it's to do with mutli-threading, there are more details
in llvm#159377.

Disable parallel loading for now so we are not spamming people
making unrelated changes.
DavidSpickett added a commit that referenced this pull request Sep 17, 2025
…159395)

Since #157170 this test has been flakey on several LLDB buildbots. I
suspect it's to do with mutli-threading, there are more details in
#159377.

Disable parallel loading for now so we are not spamming people making
unrelated changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants