Skip to content

Commit 4e4ca8e

Browse files
committed
Read and store gnu build id from loaded core file
1 parent 3ca428c commit 4e4ca8e

File tree

2 files changed

+97
-4
lines changed

2 files changed

+97
-4
lines changed

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

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include <cstddef>
910
#include <cstdlib>
1011

1112
#include <memory>
1213
#include <mutex>
14+
#include <tuple>
1315

16+
#include "Plugins/ObjectFile/ELF/ELFHeader.h"
1417
#include "lldb/Core/Module.h"
1518
#include "lldb/Core/ModuleSpec.h"
1619
#include "lldb/Core/PluginManager.h"
@@ -33,6 +36,7 @@
3336
#include "Plugins/Process/elf-core/RegisterUtilities.h"
3437
#include "ProcessElfCore.h"
3538
#include "ThreadElfCore.h"
39+
#include "lldb/lldb-types.h"
3640

3741
using namespace lldb_private;
3842
namespace ELF = llvm::ELF;
@@ -250,6 +254,9 @@ Status ProcessElfCore::DoLoadCore() {
250254
}
251255
}
252256

257+
// Try to find gnu build id before we load the executable.
258+
UpdateBuildIdForNTFileEntries();
259+
253260
// Core files are useless without the main executable. See if we can locate
254261
// the main executable using data we found in the core file notes.
255262
lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
@@ -258,6 +265,7 @@ Status ProcessElfCore::DoLoadCore() {
258265
if (!m_nt_file_entries.empty()) {
259266
ModuleSpec exe_module_spec;
260267
exe_module_spec.GetArchitecture() = arch;
268+
exe_module_spec.GetUUID() = m_nt_file_entries[0].uuid;
261269
exe_module_spec.GetFileSpec().SetFile(m_nt_file_entries[0].path,
262270
FileSpec::Style::native);
263271
if (exe_module_spec.GetFileSpec()) {
@@ -271,6 +279,17 @@ Status ProcessElfCore::DoLoadCore() {
271279
return error;
272280
}
273281

282+
void ProcessElfCore::UpdateBuildIdForNTFileEntries() {
283+
if (!m_nt_file_entries.empty()) {
284+
for (NT_FILE_Entry &entry : m_nt_file_entries) {
285+
std::optional<UUID> uuid =
286+
FindNoteInCoreMemory(entry.start, llvm::ELF::NT_GNU_BUILD_ID);
287+
if (uuid)
288+
entry.uuid = uuid.value();
289+
}
290+
}
291+
}
292+
274293
lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
275294
if (m_dyld_up.get() == nullptr)
276295
m_dyld_up.reset(DynamicLoader::FindPlugin(
@@ -570,11 +589,13 @@ static void ParseOpenBSDProcInfo(ThreadData &thread_data,
570589
}
571590

572591
llvm::Expected<std::vector<CoreNote>>
573-
ProcessElfCore::parseSegment(const DataExtractor &segment) {
592+
ProcessElfCore::parseSegment(const DataExtractor &segment,
593+
unsigned long segment_size) {
574594
lldb::offset_t offset = 0;
575595
std::vector<CoreNote> result;
576-
577-
while (offset < segment.GetByteSize()) {
596+
unsigned long note_size =
597+
segment_size == 0 ? segment.GetByteSize() : segment_size;
598+
while (offset < note_size) {
578599
ELFNote note = ELFNote();
579600
if (!note.Parse(segment, &offset))
580601
return llvm::make_error<llvm::StringError>(
@@ -983,6 +1004,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
9831004
}
9841005
}
9851006

1007+
bool ProcessElfCore::IsElf(lldb::addr_t address) {
1008+
uint8_t buf[4];
1009+
Status error;
1010+
size_t byte_read = ReadMemory(address, buf, 4, error);
1011+
if (byte_read != 4)
1012+
return false;
1013+
return elf::ELFHeader::MagicBytesMatch(buf);
1014+
}
1015+
1016+
std::optional<UUID> ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address,
1017+
uint32_t type) {
1018+
if (!IsElf(address))
1019+
return std::nullopt;
1020+
const uint32_t addr_size = GetAddressByteSize();
1021+
const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr)
1022+
: sizeof(llvm::ELF::Elf64_Ehdr);
1023+
1024+
unsigned char buf[4096];
1025+
Status error;
1026+
size_t byte_read = ReadMemory(address, buf, elf_header_size, error);
1027+
if (byte_read != elf_header_size)
1028+
return std::nullopt;
1029+
DataExtractor data(buf, 4096, GetByteOrder(), addr_size);
1030+
lldb::offset_t offset = 0;
1031+
1032+
elf::ELFHeader elf_header;
1033+
elf_header.Parse(data, &offset);
1034+
1035+
const lldb::addr_t ph_addr = address + elf_header.e_phoff;
1036+
1037+
for (unsigned int i = 0; i < elf_header.e_phnum; ++i) {
1038+
byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf,
1039+
elf_header.e_phentsize, error);
1040+
if (byte_read != elf_header.e_phentsize)
1041+
break;
1042+
offset = 0;
1043+
elf::ELFProgramHeader program_header;
1044+
program_header.Parse(data, &offset);
1045+
if (program_header.p_type != llvm::ELF::PT_NOTE)
1046+
continue;
1047+
1048+
byte_read =
1049+
ReadMemory(program_header.p_vaddr, buf, program_header.p_memsz, error);
1050+
if (byte_read != program_header.p_memsz)
1051+
continue;
1052+
1053+
auto notes_or_error = parseSegment(data, program_header.p_memsz);
1054+
if (!notes_or_error)
1055+
return std::nullopt;
1056+
for (const CoreNote &note : *notes_or_error) {
1057+
if (note.info.n_namesz == 4 && note.info.n_type == type) {
1058+
if ("GNU" == note.info.n_name)
1059+
return UUID(llvm::ArrayRef<uint8_t>(
1060+
note.data.GetDataStart(), note.info.n_descsz /*byte size*/));
1061+
}
1062+
}
1063+
}
1064+
return std::nullopt;
1065+
}
1066+
9861067
uint32_t ProcessElfCore::GetNumThreadContexts() {
9871068
if (!m_thread_data_valid)
9881069
DoLoadCore();

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
117117
lldb::addr_t end;
118118
lldb::addr_t file_ofs;
119119
std::string path;
120+
lldb_private::UUID uuid; //.note.gnu.build-id
120121
};
121122

122123
// For ProcessElfCore only
@@ -158,6 +159,16 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
158159
// Returns number of thread contexts stored in the core file
159160
uint32_t GetNumThreadContexts();
160161

162+
// Populate gnu uuid for each NT_FILE entry
163+
void UpdateBuildIdForNTFileEntries();
164+
165+
// Returns the value of certain type of note of a given start address
166+
std::optional<lldb_private::UUID> FindNoteInCoreMemory(lldb::addr_t address,
167+
uint32_t type);
168+
169+
// Returns true if the given address is a start of ELF file
170+
bool IsElf(lldb::addr_t address);
171+
161172
// Parse a contiguous address range of the process from LOAD segment
162173
lldb::addr_t
163174
AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header);
@@ -167,7 +178,8 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
167178
AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header);
168179

169180
llvm::Expected<std::vector<lldb_private::CoreNote>>
170-
parseSegment(const lldb_private::DataExtractor &segment);
181+
parseSegment(const lldb_private::DataExtractor &segment,
182+
unsigned long segment_size = 0);
171183
llvm::Error parseFreeBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
172184
llvm::Error parseNetBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
173185
llvm::Error parseOpenBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);

0 commit comments

Comments
 (0)