Skip to content

Read and store gnu build id from loaded core file #92492

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

Merged
merged 3 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ Status ProcessElfCore::DoLoadCore() {
}
}

// Try to find gnu build id before we load the executable.
UpdateBuildIdForNTFileEntries();

// Core files are useless without the main executable. See if we can locate
// the main executable using data we found in the core file notes.
lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
Expand All @@ -258,6 +261,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()) {
Expand All @@ -271,6 +275,12 @@ Status ProcessElfCore::DoLoadCore() {
return error;
}

void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
for (NT_FILE_Entry &entry : m_nt_file_entries) {
entry.uuid = FindBuidIdInCoreMemory(entry.start);
}
}

lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
if (m_dyld_up.get() == nullptr)
m_dyld_up.reset(DynamicLoader::FindPlugin(
Expand Down Expand Up @@ -983,6 +993,67 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
}
}

UUID ProcessElfCore::FindBuidIdInCoreMemory(lldb::addr_t address) {
UUID invalid_uuid;
const uint32_t addr_size = GetAddressByteSize();
const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr)
: sizeof(llvm::ELF::Elf64_Ehdr);

std::vector<uint8_t> elf_header_bytes;
elf_header_bytes.resize(elf_header_size);
Status error;
size_t byte_read =
ReadMemory(address, elf_header_bytes.data(), elf_header_size, error);
if (byte_read != elf_header_size ||
!elf::ELFHeader::MagicBytesMatch(elf_header_bytes.data()))
return invalid_uuid;
DataExtractor elf_header_data(elf_header_bytes.data(), elf_header_size,
GetByteOrder(), addr_size);
lldb::offset_t offset = 0;

elf::ELFHeader elf_header;
elf_header.Parse(elf_header_data, &offset);

const lldb::addr_t ph_addr = address + elf_header.e_phoff;

std::vector<uint8_t> ph_bytes;
ph_bytes.resize(elf_header.e_phentsize);
for (unsigned int i = 0; i < elf_header.e_phnum; ++i) {
byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize,
ph_bytes.data(), elf_header.e_phentsize, error);
if (byte_read != elf_header.e_phentsize)
break;
DataExtractor program_header_data(ph_bytes.data(), elf_header.e_phentsize,
GetByteOrder(), addr_size);
offset = 0;
elf::ELFProgramHeader program_header;
program_header.Parse(program_header_data, &offset);
if (program_header.p_type != llvm::ELF::PT_NOTE)
continue;

std::vector<uint8_t> note_bytes;
note_bytes.resize(program_header.p_memsz);

byte_read = ReadMemory(program_header.p_vaddr, note_bytes.data(),
program_header.p_memsz, error);
if (byte_read != program_header.p_memsz)
continue;
DataExtractor segment_data(note_bytes.data(), note_bytes.size(),
GetByteOrder(), addr_size);
auto notes_or_error = parseSegment(segment_data);
if (!notes_or_error)
return invalid_uuid;
for (const CoreNote &note : *notes_or_error) {
if (note.info.n_namesz == 4 &&
note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID &&
"GNU" == note.info.n_name &&
note.data.ValidOffsetForDataOfSize(0, note.info.n_descsz))
return UUID(note.data.GetData().take_front(note.info.n_descsz));
}
}
return invalid_uuid;
}

uint32_t ProcessElfCore::GetNumThreadContexts() {
if (!m_thread_data_valid)
DoLoadCore();
Expand Down
10 changes: 10 additions & 0 deletions lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
lldb::addr_t end;
lldb::addr_t file_ofs;
std::string path;
// Add a UUID member for convenient access. The UUID value is not in the
// NT_FILE entries, we will find it in core memory and store it here for
// easy access.
lldb_private::UUID uuid;
};

// For ProcessElfCore only
Expand Down Expand Up @@ -158,6 +162,12 @@ 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 value of certain type of note of a given start address
lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address);

// Parse a contiguous address range of the process from LOAD segment
lldb::addr_t
AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header);
Expand Down
Loading