-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Read and store gnu build id from loaded core file #92078
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,10 +6,12 @@ | |
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include <cstddef> | ||
#include <cstdlib> | ||
|
||
#include <memory> | ||
#include <mutex> | ||
#include <tuple> | ||
|
||
#include "lldb/Core/Module.h" | ||
#include "lldb/Core/ModuleSpec.h" | ||
|
@@ -210,6 +212,9 @@ Status ProcessElfCore::DoLoadCore() { | |
} | ||
} | ||
|
||
// We need to update uuid after address range is populated. | ||
UpdateBuildIdForNTFileEntries(); | ||
|
||
if (!ranges_are_sorted) { | ||
m_core_aranges.Sort(); | ||
m_core_range_infos.Sort(); | ||
|
@@ -258,6 +263,7 @@ Status ProcessElfCore::DoLoadCore() { | |
if (!m_nt_file_entries.empty()) { | ||
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, | ||
FileSpec::Style::native); | ||
if (exe_module_spec.GetFileSpec()) { | ||
|
@@ -271,6 +277,16 @@ Status ProcessElfCore::DoLoadCore() { | |
return error; | ||
} | ||
|
||
void ProcessElfCore::UpdateBuildIdForNTFileEntries() { | ||
if (!m_nt_file_entries.empty()) { | ||
for (NT_FILE_Entry &entry : m_nt_file_entries) { | ||
std::optional<UUID> uuid = FindBuildId(entry); | ||
if (uuid) | ||
entry.uuid = uuid.value(); | ||
} | ||
} | ||
} | ||
|
||
lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() { | ||
if (m_dyld_up.get() == nullptr) | ||
m_dyld_up.reset(DynamicLoader::FindPlugin( | ||
|
@@ -983,6 +999,40 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( | |
} | ||
} | ||
|
||
bool ProcessElfCore::IsElf(const NT_FILE_Entry entry) { | ||
size_t size = strlen(llvm::ELF::ElfMagic); | ||
uint8_t buf[size]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can allocate a buffer of 4 and read it. |
||
Status error; | ||
size_t byte_read = ReadMemory(entry.start, buf, size, error); | ||
if (byte_read == size) | ||
return memcmp(llvm::ELF::ElfMagic, buf, size) == 0; | ||
else | ||
return false; | ||
} | ||
|
||
std::optional<UUID> ProcessElfCore::FindBuildId(const NT_FILE_Entry entry) { | ||
if (!IsElf(entry)) | ||
return std::nullopt; | ||
// Build ID is stored in the ELF file as a section named ".note.gnu.build-id" | ||
uint8_t gnu_build_id_bytes[8] = {0x03, 0x00, 0x00, 0x00, | ||
0x47, 0x4e, 0x55, 0x00}; | ||
lldb::addr_t gnu_build_id_addr = | ||
FindInMemory(entry.start, entry.end, gnu_build_id_bytes, 8); | ||
if (gnu_build_id_addr == LLDB_INVALID_ADDRESS) | ||
return std::nullopt; | ||
uint8_t buf[36]; | ||
Status error; | ||
size_t byte_read = ReadMemory(gnu_build_id_addr - 8, buf, 36, error); | ||
// .note.gnu.build-id starts with 04 00 00 00 {id_byte_size} 00 00 00 03 00 00 | ||
// 00 47 4e 55 00 | ||
Comment on lines
+1026
to
+1027
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be better said as:
|
||
if (byte_read == 36) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should not assume there are always 36 bytes here. We should read the first 8 bytes to get the
|
||
if (buf[0] == 0x04) { | ||
return UUID(llvm::ArrayRef<uint8_t>(buf + 16, buf[4] /*byte size*/)); | ||
} | ||
} | ||
Comment on lines
+1028
to
+1032
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove braces per llvm coding guidelines for single statement |
||
return std::nullopt; | ||
} | ||
|
||
uint32_t ProcessElfCore::GetNumThreadContexts() { | ||
if (!m_thread_data_valid) | ||
DoLoadCore(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -117,6 +117,8 @@ class ProcessElfCore : public lldb_private::PostMortemProcess { | |
lldb::addr_t end; | ||
lldb::addr_t file_ofs; | ||
std::string path; | ||
lldb_private::UUID | ||
uuid; // extracted from .note.gnu.build-id section from core file | ||
Comment on lines
+120
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we should use |
||
}; | ||
|
||
// For ProcessElfCore only | ||
|
@@ -158,6 +160,15 @@ class ProcessElfCore : public lldb_private::PostMortemProcess { | |
// Returns number of thread contexts stored in the core file | ||
uint32_t GetNumThreadContexts(); | ||
|
||
// Populate gnu uuid for each NT_FILE entry | ||
void UpdateBuildIdForNTFileEntries(); | ||
|
||
// Returns the UUID of a given NT_FILE entry | ||
std::optional<lldb_private::UUID> FindBuildId(const NT_FILE_Entry entry); | ||
|
||
// Returns true if the given NT_FILE entry is an ELF file | ||
bool IsElf(const NT_FILE_Entry entry); | ||
|
||
// Parse a contiguous address range of the process from LOAD segment | ||
lldb::addr_t | ||
AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is efficient only because our process caches memory on its own... Otherwise reading memory 1 byte at a time would be more expensive. Not sure if we can get any speed up by reading more than one byte at a time and then using our own internal buffer.