Skip to content

Commit c087da4

Browse files
GeorgeHuyuboGeorge Hu
andauthored
[lldb][ElfCore] Improve main executable detection in core files (#157170)
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 Co-authored-by: George Hu <[email protected]>
1 parent c04b98f commit c087da4

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
lines changed

lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
9999
ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp,
100100
lldb::ListenerSP listener_sp,
101101
const FileSpec &core_file)
102-
: PostMortemProcess(target_sp, listener_sp, core_file) {}
102+
: PostMortemProcess(target_sp, listener_sp, core_file), m_uuids() {}
103103

104104
// Destructor
105105
ProcessElfCore::~ProcessElfCore() {
@@ -257,12 +257,12 @@ Status ProcessElfCore::DoLoadCore() {
257257
// the main executable using data we found in the core file notes.
258258
lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
259259
if (!exe_module_sp) {
260-
// The first entry in the NT_FILE might be our executable
261260
if (!m_nt_file_entries.empty()) {
261+
llvm::StringRef executable_path = GetMainExecutablePath();
262262
ModuleSpec exe_module_spec;
263263
exe_module_spec.GetArchitecture() = arch;
264-
exe_module_spec.GetUUID() = m_nt_file_entries[0].uuid;
265-
exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path,
264+
exe_module_spec.GetUUID() = FindModuleUUID(executable_path);
265+
exe_module_spec.GetFileSpec().SetFile(executable_path,
266266
FileSpec::Style::native);
267267
if (exe_module_spec.GetFileSpec()) {
268268
exe_module_sp =
@@ -277,21 +277,38 @@ Status ProcessElfCore::DoLoadCore() {
277277

278278
void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
279279
Log *log = GetLog(LLDBLog::Process);
280+
m_uuids.clear();
280281
for (NT_FILE_Entry &entry : m_nt_file_entries) {
281-
entry.uuid = FindBuidIdInCoreMemory(entry.start);
282-
if (log && entry.uuid.IsValid())
283-
LLDB_LOGF(log, "%s found UUID @ %16.16" PRIx64 ": %s \"%s\"",
284-
__FUNCTION__, entry.start, entry.uuid.GetAsString().c_str(),
285-
entry.path.c_str());
282+
UUID uuid = FindBuidIdInCoreMemory(entry.start);
283+
if (uuid.IsValid()) {
284+
// Assert that either the path is not in the map or the UUID matches
285+
assert(m_uuids.count(entry.path) == 0 || m_uuids[entry.path] == uuid);
286+
m_uuids[entry.path] = uuid;
287+
if (log)
288+
LLDB_LOGF(log, "%s found UUID @ %16.16" PRIx64 ": %s \"%s\"",
289+
__FUNCTION__, entry.start, uuid.GetAsString().c_str(),
290+
entry.path.c_str());
291+
}
286292
}
287293
}
288294

295+
llvm::StringRef ProcessElfCore::GetMainExecutablePath() {
296+
if (m_nt_file_entries.empty())
297+
return "";
298+
299+
// The first entry in the NT_FILE might be our executable
300+
llvm::StringRef executable_path = m_nt_file_entries[0].path;
301+
// Prefer the NT_FILE entry matching m_executable_name as main executable.
302+
for (const NT_FILE_Entry &file_entry : m_nt_file_entries)
303+
if (llvm::StringRef(file_entry.path).ends_with("/" + m_executable_name)) {
304+
executable_path = file_entry.path;
305+
break;
306+
}
307+
return executable_path;
308+
}
309+
289310
UUID ProcessElfCore::FindModuleUUID(const llvm::StringRef path) {
290-
// Returns the gnu uuid from matched NT_FILE entry
291-
for (NT_FILE_Entry &entry : m_nt_file_entries)
292-
if (path == entry.path && entry.uuid.IsValid())
293-
return entry.uuid;
294-
return UUID();
311+
return m_uuids[std::string(path)];
295312
}
296313

297314
lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
@@ -935,6 +952,7 @@ llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) {
935952
return status.ToError();
936953
thread_data.name.assign (prpsinfo.pr_fname, strnlen (prpsinfo.pr_fname, sizeof (prpsinfo.pr_fname)));
937954
SetID(prpsinfo.pr_pid);
955+
m_executable_name = prpsinfo.pr_fname;
938956
break;
939957
}
940958
case ELF::NT_SIGINFO: {

lldb/source/Plugins/Process/elf-core/ProcessElfCore.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H
1818

1919
#include <list>
20+
#include <unordered_map>
2021
#include <vector>
2122

2223
#include "lldb/Target/PostMortemProcess.h"
@@ -115,10 +116,6 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
115116
lldb::addr_t end;
116117
lldb::addr_t file_ofs;
117118
std::string path;
118-
// Add a UUID member for convenient access. The UUID value is not in the
119-
// NT_FILE entries, we will find it in core memory and store it here for
120-
// easy access.
121-
lldb_private::UUID uuid;
122119
};
123120

124121
// For ProcessElfCore only
@@ -152,6 +149,12 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
152149
// NT_FILE entries found from the NOTE segment
153150
std::vector<NT_FILE_Entry> m_nt_file_entries;
154151

152+
// Map from file path to UUID for quick lookup
153+
std::unordered_map<std::string, lldb_private::UUID> m_uuids;
154+
155+
// Executable name found from the ELF PRPSINFO
156+
std::string m_executable_name;
157+
155158
// Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
156159
llvm::Error ParseThreadContextsFromNoteSegment(
157160
const elf::ELFProgramHeader &segment_header,
@@ -165,6 +168,9 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
165168

166169
lldb_private::UUID FindModuleUUID(const llvm::StringRef path) override;
167170

171+
// Returns the main executable path
172+
llvm::StringRef GetMainExecutablePath();
173+
168174
// Returns the value of certain type of note of a given start address
169175
lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address);
170176

0 commit comments

Comments
 (0)