[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo closed https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492 >From a9714b155a116e9b1d18434c0485ea2ad35680f3 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH 1/3] Read and store gnu build id from loaded core file --- .../Process/elf-core/ProcessElfCore.cpp | 74 ++- .../Plugins/Process/elf-core/ProcessElfCore.h | 10 +++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..0e0937b77f4b4 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -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(); @@ -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()) { @@ -271,6 +275,14 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_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( @@ -573,7 +585,6 @@ llvm::Expected> ProcessElfCore::parseSegment(const DataExtractor ) { lldb::offset_t offset = 0; std::vector result; - while (offset < segment.GetByteSize()) { ELFNote note = ELFNote(); if (!note.Parse(segment, )) @@ -983,6 +994,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); + + // 80 bytes buffer is larger enough for the ELF header or program headers + unsigned char buf[80]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size || !elf::ELFHeader::MagicBytesMatch(buf)) +return invalid_uuid; + assert(sizeof(buf) >= elf_header_size); + DataExtractor elf_header_data(buf, elf_header_size, GetByteOrder(), +addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +assert(sizeof(buf) >= elf_header.e_phentsize); +DataExtractor program_header_data(buf, elf_header.e_phentsize, + GetByteOrder(), addr_size); +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(program_header_data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +std::vector 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; +assert(sizeof(buf) >= program_header.p_memsz); +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 : *notes_or_error) { + if (note.info.n_namesz == 4 && + note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID) { +if ("GNU" == note.info.n_name) + return UUID(llvm::ArrayRef( + note.data.GetDataStart(), note.info.n_descsz /*byte size*/)); + } +} + } + return invalid_uuid; +} + uint32_t ProcessElfCore::GetNumThreadContexts() { if (!m_thread_data_valid) DoLoadCore(); diff --git
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492 >From a9714b155a116e9b1d18434c0485ea2ad35680f3 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH 1/3] Read and store gnu build id from loaded core file --- .../Process/elf-core/ProcessElfCore.cpp | 74 ++- .../Plugins/Process/elf-core/ProcessElfCore.h | 10 +++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..0e0937b77f4b4 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -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(); @@ -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()) { @@ -271,6 +275,14 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_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( @@ -573,7 +585,6 @@ llvm::Expected> ProcessElfCore::parseSegment(const DataExtractor ) { lldb::offset_t offset = 0; std::vector result; - while (offset < segment.GetByteSize()) { ELFNote note = ELFNote(); if (!note.Parse(segment, )) @@ -983,6 +994,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); + + // 80 bytes buffer is larger enough for the ELF header or program headers + unsigned char buf[80]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size || !elf::ELFHeader::MagicBytesMatch(buf)) +return invalid_uuid; + assert(sizeof(buf) >= elf_header_size); + DataExtractor elf_header_data(buf, elf_header_size, GetByteOrder(), +addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +assert(sizeof(buf) >= elf_header.e_phentsize); +DataExtractor program_header_data(buf, elf_header.e_phentsize, + GetByteOrder(), addr_size); +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(program_header_data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +std::vector 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; +assert(sizeof(buf) >= program_header.p_memsz); +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 : *notes_or_error) { + if (note.info.n_namesz == 4 && + note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID) { +if ("GNU" == note.info.n_name) + return UUID(llvm::ArrayRef( + note.data.GetDataStart(), note.info.n_descsz /*byte size*/)); + } +} + } + return invalid_uuid; +} + uint32_t ProcessElfCore::GetNumThreadContexts() { if (!m_thread_data_valid) DoLoadCore(); diff --git
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
labath wrote: Thanks for your patience. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -271,6 +275,14 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { labath wrote: No need to explicitly check for emptyness. The loop will naturally do nothing if the array is empty. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -573,7 +585,6 @@ llvm::Expected> ProcessElfCore::parseSegment(const DataExtractor ) { lldb::offset_t offset = 0; std::vector result; - labath wrote: I know why this came to be, but it'd be nice to revert it so the final patch does not contain a spurious newline edit. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/labath approved this pull request. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/labath edited https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492 >From a9714b155a116e9b1d18434c0485ea2ad35680f3 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH 1/2] Read and store gnu build id from loaded core file --- .../Process/elf-core/ProcessElfCore.cpp | 74 ++- .../Plugins/Process/elf-core/ProcessElfCore.h | 10 +++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..0e0937b77f4b4 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -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(); @@ -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()) { @@ -271,6 +275,14 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_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( @@ -573,7 +585,6 @@ llvm::Expected> ProcessElfCore::parseSegment(const DataExtractor ) { lldb::offset_t offset = 0; std::vector result; - while (offset < segment.GetByteSize()) { ELFNote note = ELFNote(); if (!note.Parse(segment, )) @@ -983,6 +994,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); + + // 80 bytes buffer is larger enough for the ELF header or program headers + unsigned char buf[80]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size || !elf::ELFHeader::MagicBytesMatch(buf)) +return invalid_uuid; + assert(sizeof(buf) >= elf_header_size); + DataExtractor elf_header_data(buf, elf_header_size, GetByteOrder(), +addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +assert(sizeof(buf) >= elf_header.e_phentsize); +DataExtractor program_header_data(buf, elf_header.e_phentsize, + GetByteOrder(), addr_size); +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(program_header_data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +std::vector 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; +assert(sizeof(buf) >= program_header.p_memsz); +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 : *notes_or_error) { + if (note.info.n_namesz == 4 && + note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID) { +if ("GNU" == note.info.n_name) + return UUID(llvm::ArrayRef( + note.data.GetDataStart(), note.info.n_descsz /*byte size*/)); + } +} + } + return invalid_uuid; +} + uint32_t ProcessElfCore::GetNumThreadContexts() { if (!m_thread_data_valid) DoLoadCore(); diff --git
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +994,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); + + // 80 bytes buffer is larger enough for the ELF header or program headers + unsigned char buf[80]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size || !elf::ELFHeader::MagicBytesMatch(buf)) +return invalid_uuid; + assert(sizeof(buf) >= elf_header_size); + DataExtractor elf_header_data(buf, elf_header_size, GetByteOrder(), +addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +assert(sizeof(buf) >= elf_header.e_phentsize); labath wrote: This could be a static_assert, but it might even be better to do declare the array as something like `char buf[sizeof(Elf64_Ehdr)] and avoid any doubt about it being large enough (then you also wouldn't need the comment above the array declaration). https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/labath commented: Very close. Just a couple of details. BTW, I believe the recommended workflow for working with pull requests is to put your new changes as additional commits on top and then squash them all together after merging. The GitHub UI just works better that way. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +994,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); + + // 80 bytes buffer is larger enough for the ELF header or program headers + unsigned char buf[80]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size || !elf::ELFHeader::MagicBytesMatch(buf)) +return invalid_uuid; + assert(sizeof(buf) >= elf_header_size); + DataExtractor elf_header_data(buf, elf_header_size, GetByteOrder(), +addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +assert(sizeof(buf) >= elf_header.e_phentsize); +DataExtractor program_header_data(buf, elf_header.e_phentsize, + GetByteOrder(), addr_size); +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(program_header_data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +std::vector 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; +assert(sizeof(buf) >= program_header.p_memsz); +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 : *notes_or_error) { + if (note.info.n_namesz == 4 && + note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID) { +if ("GNU" == note.info.n_name) + return UUID(llvm::ArrayRef( + note.data.GetDataStart(), note.info.n_descsz /*byte size*/)); labath wrote: In case of a corrupted core file, `note.data` can contain less than `n_descsz` bytes, and this will create a invalid ArrayRef (and possibly crash lldb). Writing this like `return UUID(note.data.GetData())` will ensure that does not happen, although it could return a truncated UUID in that case. If you want to check that case explicitly, then I'd recommend something like: ``` if(note.data.ValidOffsetForDataOfSize(0, note.info.n_descsz)) return UUID(note.data.GetData().take_front(note.info.n_descsz); ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/labath edited https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +994,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); + + // 80 bytes buffer is larger enough for the ELF header or program headers + unsigned char buf[80]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size || !elf::ELFHeader::MagicBytesMatch(buf)) +return invalid_uuid; + assert(sizeof(buf) >= elf_header_size); + DataExtractor elf_header_data(buf, elf_header_size, GetByteOrder(), +addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +assert(sizeof(buf) >= elf_header.e_phentsize); +DataExtractor program_header_data(buf, elf_header.e_phentsize, + GetByteOrder(), addr_size); +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(program_header_data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +std::vector 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; +assert(sizeof(buf) >= program_header.p_memsz); labath wrote: This looks like an obsolete assertion as the program headers are read into a dynamically sized vector now. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492 >From a9714b155a116e9b1d18434c0485ea2ad35680f3 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH] Read and store gnu build id from loaded core file --- .../Process/elf-core/ProcessElfCore.cpp | 74 ++- .../Plugins/Process/elf-core/ProcessElfCore.h | 10 +++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..0e0937b77f4b4 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -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(); @@ -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()) { @@ -271,6 +275,14 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_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( @@ -573,7 +585,6 @@ llvm::Expected> ProcessElfCore::parseSegment(const DataExtractor ) { lldb::offset_t offset = 0; std::vector result; - while (offset < segment.GetByteSize()) { ELFNote note = ELFNote(); if (!note.Parse(segment, )) @@ -983,6 +994,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); + + // 80 bytes buffer is larger enough for the ELF header or program headers + unsigned char buf[80]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size || !elf::ELFHeader::MagicBytesMatch(buf)) +return invalid_uuid; + assert(sizeof(buf) >= elf_header_size); + DataExtractor elf_header_data(buf, elf_header_size, GetByteOrder(), +addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +assert(sizeof(buf) >= elf_header.e_phentsize); +DataExtractor program_header_data(buf, elf_header.e_phentsize, + GetByteOrder(), addr_size); +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(program_header_data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +std::vector 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; +assert(sizeof(buf) >= program_header.p_memsz); +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 : *notes_or_error) { + if (note.info.n_namesz == 4 && + note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID) { +if ("GNU" == note.info.n_name) + return UUID(llvm::ArrayRef( + note.data.GetDataStart(), note.info.n_descsz /*byte size*/)); + } +} + } + return invalid_uuid; +} + uint32_t ProcessElfCore::GetNumThreadContexts() { if (!m_thread_data_valid) DoLoadCore(); diff --git
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/labath edited https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -271,6 +282,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { labath wrote: Makes sense. I though something like this might be the case. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1001,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address, + uint32_t type) { labath wrote: I don't think this `type` argument is useful, as this function already a UUID, and so it can't be used to parse any other kind of a note. I'd recommend inlining NT_GNU_BUILD_ID into the function (and renaming it to something like FindBuidIdInCoreMemory). https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1001,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; labath wrote: I think you can just delete this and put the magic bytes check at on line ~1024, after you read the full header. Reading 4 bytes is not going to be appreciably faster than reading 64 (sizeof(Elf64_Ehdr)), and this will make the code look more like the one on lines 60--70 (which essentially does the same thing). https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -271,6 +276,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_Entry : m_nt_file_entries) { + std::optional uuid = labath wrote: Since UUID already has an IsValid() method I don't think wrapping it in an optional is not going to help (in fact, it will add ambiguity: Does returning an invalid UUID mean something different than std::nullopt?) Up to you, but I'd remove the optional here... https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -570,11 +586,13 @@ static void ParseOpenBSDProcInfo(ThreadData _data, } llvm::Expected> -ProcessElfCore::parseSegment(const DataExtractor ) { +ProcessElfCore::parseSegment(const DataExtractor , + unsigned long segment_size) { lldb::offset_t offset = 0; std::vector result; - - while (offset < segment.GetByteSize()) { + unsigned long note_size = + segment_size == 0 ? segment.GetByteSize() : segment_size; + while (offset < note_size) { clayborg wrote: revert this, we will trim the size of the data down before passing it in. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1001,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address, + uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + 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); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size) +return std::nullopt; + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +byte_read = +ReadMemory(program_header.p_vaddr, buf, program_header.p_memsz, error); +if (byte_read != program_header.p_memsz) + continue; + +auto notes_or_error = parseSegment(data, program_header.p_memsz); clayborg wrote: Create a DataBuffer for only the note data, and then we won't need to pass the `program_header.p_memsz` to `parseSegment(...)`: ``` DataExtractor note_data(note_bytes.data(), note_bytes.size(), GetByteOrder(), addr_size); auto notes_or_error = parseSegment(note_data); ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1001,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address, + uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + 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); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size) +return std::nullopt; + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(data, ); clayborg wrote: Use `header_data` to only allow access to the bytes we read. ``` elf_header.Parse(header_data, ); ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1001,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address, + uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + 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); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size) +return std::nullopt; + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(data, ); clayborg wrote: Create a `DataExtractor` that contains only a program header worth of data: ``` assert(sizeof(buf) >= elf_header.e_phentsize); DataExtractor phdr_data(buf, elf_header.e_phentsize, GetByteOrder(), addr_size); program_header.Parse(phdr_data, ); ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1001,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address, + uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + 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); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size) +return std::nullopt; + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +byte_read = +ReadMemory(program_header.p_vaddr, buf, program_header.p_memsz, error); clayborg wrote: Make a dynamic memory buffer to make sure we have enough bytes to store the note data as it could exceed 4096 bytes, and then read into this buffer: ``` std::vector note_bytes; note_bytes.resize(program_header.p_memsz); byte_read = ReadMemory(note_bytes.data(), note_bytes.size(), program_header.p_memsz, error); ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -117,6 +117,7 @@ class ProcessElfCore : public lldb_private::PostMortemProcess { lldb::addr_t end; lldb::addr_t file_ofs; std::string path; +lldb_private::UUID uuid; //.note.gnu.build-id clayborg wrote: Add a comment letting the user know the UUID isn't actually in the NT_FILE_Entry: ``` // 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. ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/clayborg requested changes to this pull request. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -570,11 +586,13 @@ static void ParseOpenBSDProcInfo(ThreadData _data, } llvm::Expected> -ProcessElfCore::parseSegment(const DataExtractor ) { +ProcessElfCore::parseSegment(const DataExtractor , + unsigned long segment_size) { clayborg wrote: Remove thuis change, we can easily trim down the size of the DataExtractor before passing it in. See inline comments below. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/clayborg edited https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1001,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address, + uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + 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); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size) +return std::nullopt; + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); clayborg wrote: It is ok to have a large buffer, but we should make sure the data extractor points to just the data we have read for each place that we use it by contructing new DataExtractor objects: ``` assert(sizeof(buf) >= elf_header_size); DataExtractor header_data(buf, elf_header_size, GetByteOrder(), addr_size); ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -167,7 +178,8 @@ class ProcessElfCore : public lldb_private::PostMortemProcess { AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader ); llvm::Expected> - parseSegment(const lldb_private::DataExtractor ); + parseSegment(const lldb_private::DataExtractor , + unsigned long segment_size = 0); clayborg wrote: revert https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492 >From 11dda0b456880005695b6d1f195060788ad0edb7 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH] Read and store gnu build id from loaded core file --- .../Process/elf-core/ProcessElfCore.cpp | 84 ++- .../Plugins/Process/elf-core/ProcessElfCore.h | 14 +++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..cc82d1c2b5132 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -11,6 +11,7 @@ #include #include +#include "Plugins/ObjectFile/ELF/ELFHeader.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -250,6 +251,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(); @@ -258,6 +262,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 +276,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_Entry : m_nt_file_entries) { + std::optional uuid = + FindNoteInCoreMemory(entry.start, llvm::ELF::NT_GNU_BUILD_ID); + if (uuid) +entry.uuid = uuid.value(); +} + } +} + lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() { if (m_dyld_up.get() == nullptr) m_dyld_up.reset(DynamicLoader::FindPlugin( @@ -570,11 +586,13 @@ static void ParseOpenBSDProcInfo(ThreadData _data, } llvm::Expected> -ProcessElfCore::parseSegment(const DataExtractor ) { +ProcessElfCore::parseSegment(const DataExtractor , + unsigned long segment_size) { lldb::offset_t offset = 0; std::vector result; - - while (offset < segment.GetByteSize()) { + unsigned long note_size = + segment_size == 0 ? segment.GetByteSize() : segment_size; + while (offset < note_size) { ELFNote note = ELFNote(); if (!note.Parse(segment, )) return llvm::make_error( @@ -983,6 +1001,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address, + uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + 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); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size) +return std::nullopt; + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +byte_read = +ReadMemory(program_header.p_vaddr, buf, program_header.p_memsz, error); +if (byte_read != program_header.p_memsz) + continue; + +auto notes_or_error = parseSegment(data, program_header.p_memsz); +if (!notes_or_error) + return std::nullopt; +for (const CoreNote : *notes_or_error) { + if (note.info.n_namesz == 4 && note.info.n_type == type) { +if ("GNU" == note.info.n_name) + return UUID(llvm::ArrayRef( + note.data.GetDataStart(),
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492 >From 4e4ca8edc4116cba0925cca8229bd5b1cb002b21 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH] Read and store gnu build id from loaded core file --- .../Process/elf-core/ProcessElfCore.cpp | 87 ++- .../Plugins/Process/elf-core/ProcessElfCore.h | 14 ++- 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..3a126220fabf0 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -6,11 +6,14 @@ // //===--===// +#include #include #include #include +#include +#include "Plugins/ObjectFile/ELF/ELFHeader.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -33,6 +36,7 @@ #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "ProcessElfCore.h" #include "ThreadElfCore.h" +#include "lldb/lldb-types.h" using namespace lldb_private; namespace ELF = llvm::ELF; @@ -250,6 +254,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(); @@ -258,6 +265,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 +279,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_Entry : m_nt_file_entries) { + std::optional uuid = + FindNoteInCoreMemory(entry.start, llvm::ELF::NT_GNU_BUILD_ID); + if (uuid) +entry.uuid = uuid.value(); +} + } +} + lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() { if (m_dyld_up.get() == nullptr) m_dyld_up.reset(DynamicLoader::FindPlugin( @@ -570,11 +589,13 @@ static void ParseOpenBSDProcInfo(ThreadData _data, } llvm::Expected> -ProcessElfCore::parseSegment(const DataExtractor ) { +ProcessElfCore::parseSegment(const DataExtractor , + unsigned long segment_size) { lldb::offset_t offset = 0; std::vector result; - - while (offset < segment.GetByteSize()) { + unsigned long note_size = + segment_size == 0 ? segment.GetByteSize() : segment_size; + while (offset < note_size) { ELFNote note = ELFNote(); if (!note.Parse(segment, )) return llvm::make_error( @@ -983,6 +1004,66 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNoteInCoreMemory(lldb::addr_t address, + uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + 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); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + if (byte_read != elf_header_size) +return std::nullopt; + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(data, ); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, buf, + elf_header.e_phentsize, error); +if (byte_read != elf_header.e_phentsize) + break; +offset = 0; +elf::ELFProgramHeader program_header; +program_header.Parse(data, ); +if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + +byte_read = +ReadMemory(program_header.p_vaddr, buf, program_header.p_memsz, error); +if (byte_read != program_header.p_memsz) + continue; + +auto
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492 >From fc7ae3cd19a999375504733be6c942978d80d5d7 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH] Read and store gnu build id from loaded core file --- .../Plugins/ObjectFile/ELF/ELFHeader.cpp | 13 +++ .../source/Plugins/ObjectFile/ELF/ELFHeader.h | 25 ++ .../Process/elf-core/ProcessElfCore.cpp | 87 +++ .../Plugins/Process/elf-core/ProcessElfCore.h | 15 4 files changed, 140 insertions(+) diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index a6e385f70709b..fcb677ed28a92 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -252,6 +252,19 @@ bool ELFSectionHeader::Parse(const lldb_private::DataExtractor , return true; } +// SectionNote + +SectionNote::SectionNote() { memset(this, 0, sizeof(SectionNote)); } + +bool SectionNote::Parse(const lldb_private::DataExtractor , +lldb::offset_t *offset) { + // Read sn_namesz and sn_descsz, sn_type. + if (data.GetU32(offset, _namesz, 3) == nullptr) +return false; + + return true; +} + // ELFSymbol ELFSymbol::ELFSymbol() { memset(this, 0, sizeof(ELFSymbol)); } diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h index 963cc850736ff..da6dfc7343bcf 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -271,6 +271,31 @@ struct ELFSymbol { const lldb_private::SectionList *section_list); }; +/// \class SectionNote +/// Represents an entry of PT_NOTE in program header +struct SectionNote { + elf_word sn_namesz; + elf_word sn_descsz; + elf_word sn_type; + + SectionNote(); + + /// Parse an SectionNote entry from the given DataExtractor starting at + /// position \p offset. + /// + /// \param[in] data + ///The DataExtractor to read from. + /// + /// \param[in,out] offset + ///Pointer to an offset in the data. On return the offset will be + ///advanced by the number of bytes read. + /// + /// \return + ///True if the SectionNote was successfully read and false + ///otherwise. + bool Parse(const lldb_private::DataExtractor , lldb::offset_t *offset); +}; + /// \class ELFDynamic /// Represents an entry in an ELF dynamic table. struct ELFDynamic { diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..4e5e70ceae438 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -6,11 +6,14 @@ // //===--===// +#include #include #include #include +#include +#include "Plugins/ObjectFile/ELF/ELFHeader.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -33,6 +36,7 @@ #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "ProcessElfCore.h" #include "ThreadElfCore.h" +#include "lldb/lldb-types.h" using namespace lldb_private; namespace ELF = llvm::ELF; @@ -250,6 +254,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(); @@ -258,6 +265,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 +279,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_Entry : m_nt_file_entries) { + std::optional uuid = + FindNoteInCoreMemory(entry.start, llvm::ELF::NT_GNU_BUILD_ID); + 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 +1002,74 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4)
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -271,6 +282,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { GeorgeHuyubo wrote: @labath There are two reasons, 1. We need to do this after we load PT_LOAD segment, so that we have address map which is essential to ReadMemory. PT_LOAD is usually after PT_NOTE afaik. 2. We need to do this after the core architecture is set, so GetAddressByteSize() will return non zero value. @kevinfrei During the pass, it's parsing the elf header of the core file, during which we don't have the gnu build id in there yet. We need to let the pass finish so that we have the core file loaded into memory, and then we will need to read from certain memory region which represent a loaded module and parse the elf header there to get the gnu build id. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo updated https://github.com/llvm/llvm-project/pull/92492 >From 304528acdd3590bf4d8d1a03e31fd0970ed2eaa2 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH] Read and store gnu build id from loaded core file --- .../Plugins/ObjectFile/ELF/ELFHeader.cpp | 13 +++ .../source/Plugins/ObjectFile/ELF/ELFHeader.h | 27 ++ .../Process/elf-core/ProcessElfCore.cpp | 87 +++ .../Plugins/Process/elf-core/ProcessElfCore.h | 15 4 files changed, 142 insertions(+) diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index a6e385f70709b..fcb677ed28a92 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -252,6 +252,19 @@ bool ELFSectionHeader::Parse(const lldb_private::DataExtractor , return true; } +// SectionNote + +SectionNote::SectionNote() { memset(this, 0, sizeof(SectionNote)); } + +bool SectionNote::Parse(const lldb_private::DataExtractor , +lldb::offset_t *offset) { + // Read sn_namesz and sn_descsz, sn_type. + if (data.GetU32(offset, _namesz, 3) == nullptr) +return false; + + return true; +} + // ELFSymbol ELFSymbol::ELFSymbol() { memset(this, 0, sizeof(ELFSymbol)); } diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h index 963cc850736ff..baf35d4a78c18 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -271,6 +271,33 @@ struct ELFSymbol { const lldb_private::SectionList *section_list); }; +/// \class SectionNote +/// Represents an entry of PT_NOTE in program header +struct SectionNote { + elf_word sn_namesz; + elf_word sn_descsz; + elf_word sn_type; + + SectionNote(); + + /// Parse an SectionNote entry from the given DataExtractor starting at + /// position \p offset. The address size of the DataExtractor determines if + /// a 32 or 64 bit object is to be parsed. + /// + /// \param[in] data + ///The DataExtractor to read from. The address size of the extractor + ///determines if a 32 or 64 bit object should be read. + /// + /// \param[in,out] offset + ///Pointer to an offset in the data. On return the offset will be + ///advanced by the number of bytes read. + /// + /// \return + ///True if the SectionNote was successfully read and false + ///otherwise. + bool Parse(const lldb_private::DataExtractor , lldb::offset_t *offset); +}; + /// \class ELFDynamic /// Represents an entry in an ELF dynamic table. struct ELFDynamic { diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 36812c27a5b6d..4e5e70ceae438 100644 --- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -6,11 +6,14 @@ // //===--===// +#include #include #include #include +#include +#include "Plugins/ObjectFile/ELF/ELFHeader.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -33,6 +36,7 @@ #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "ProcessElfCore.h" #include "ThreadElfCore.h" +#include "lldb/lldb-types.h" using namespace lldb_private; namespace ELF = llvm::ELF; @@ -250,6 +254,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(); @@ -258,6 +265,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 +279,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { +for (NT_FILE_Entry : m_nt_file_entries) { + std::optional uuid = + FindNoteInCoreMemory(entry.start, llvm::ELF::NT_GNU_BUILD_ID); + 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 +1002,74 @@ llvm::Error
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1005,73 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(const lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNote(const lldb::addr_t address, + const uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + const uint32_t addr_size = GetAddressByteSize(); + const lldb::offset_t ehdr_phoff_offset = ELFOFFSETOF(Ehdr, e_phoff); + const lldb::offset_t ehdr_phentsize_offset = ELFOFFSETOF(Ehdr, e_phentsize); + const lldb::offset_t ehdr_phnum_offset = ELFOFFSETOF(Ehdr, e_phnum); + const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr) +: sizeof(llvm::ELF::Elf64_Ehdr); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = ehdr_phoff_offset; + lldb::offset_t phoff = data.GetAddress(); + + offset = ehdr_phentsize_offset; + lldb::offset_t phentsize = data.GetU16(); + offset = ehdr_phnum_offset; + lldb::offset_t phnum = data.GetU16(); clayborg wrote: header for the `ELFHeader` class is in: ``` lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1005,73 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(const lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNote(const lldb::addr_t address, + const uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + const uint32_t addr_size = GetAddressByteSize(); + const lldb::offset_t ehdr_phoff_offset = ELFOFFSETOF(Ehdr, e_phoff); + const lldb::offset_t ehdr_phentsize_offset = ELFOFFSETOF(Ehdr, e_phentsize); + const lldb::offset_t ehdr_phnum_offset = ELFOFFSETOF(Ehdr, e_phnum); clayborg wrote: pass `addr_size` to the macro https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -1649,6 +1679,26 @@ class Process : public std::enable_shared_from_this, lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status ); + /// Find a string within a memory region. + /// + /// This function searches for the string represented by the provided buffer + /// within the memory range specified by the low and high addresses. It uses + /// a bad character heuristic to optimize the search process. + /// + /// \param[in] low The starting address of the memory region to be searched. + /// + /// \param[in] high The ending address of the memory region to be searched. + /// + /// \param[in] buffer A pointer to the buffer containing the string to be + /// searched. clayborg wrote: ``` /// \param[in] buffer A pointer to the buffer containing the bytes to be /// searched. ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -33,12 +35,17 @@ #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "ProcessElfCore.h" #include "ThreadElfCore.h" +#include "lldb/lldb-types.h" using namespace lldb_private; namespace ELF = llvm::ELF; LLDB_PLUGIN_DEFINE(ProcessElfCore) +#define ELFOFFSETOF(T, M) \ + addr_size == 4 ? offsetof(llvm::ELF::Elf32_##T, M) \ + : offsetof(llvm::ELF::Elf64_##T, M) clayborg wrote: We should pass in `addr_size` here: ``` #define ELFOFFSETOF(type_name, member, addr_size) ... ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -117,6 +117,13 @@ class ProcessElfCore : public lldb_private::PostMortemProcess { lldb::addr_t end; lldb::addr_t file_ofs; std::string path; +lldb_private::UUID uuid; //.note.gnu.build-id + }; + + struct Section_Note { +uint32_t namesz; +uint32_t descsz; +uint32_t type; clayborg wrote: or move it into ELFHeader.h and then add a parse method. We are using a ton of stuff already from ELFHeader.h, so we should follow that path https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1005,73 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(const lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNote(const lldb::addr_t address, clayborg wrote: Maybe the name of `FindNoteInCoreMemory`? https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -1649,6 +1679,26 @@ class Process : public std::enable_shared_from_this, lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status ); + /// Find a string within a memory region. clayborg wrote: Change to: ``` /// Find bytes within a memory range. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -1649,6 +1679,26 @@ class Process : public std::enable_shared_from_this, lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status ); + /// Find a string within a memory region. + /// + /// This function searches for the string represented by the provided buffer clayborg wrote: change to: ``` /// This function searches for the bytes represented by the provided buffer ``` https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -117,6 +117,13 @@ class ProcessElfCore : public lldb_private::PostMortemProcess { lldb::addr_t end; lldb::addr_t file_ofs; std::string path; +lldb_private::UUID uuid; //.note.gnu.build-id + }; + + struct Section_Note { +uint32_t namesz; +uint32_t descsz; +uint32_t type; kevinfrei wrote: Move this to the ThreadElfCore.h header and add a 'parse' method to it, so the UUID is populated much like the PRPSINFO data and other useful info from the coredump. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/kevinfrei edited https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/kevinfrei requested changes to this pull request. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -271,6 +282,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { kevinfrei wrote: I'd suggest adding it to that pass as well, though it will be a little bit messier, as NT_PRPSINFO and NT_GNU_BUILD_ID have the same values, so they depend on the Name field (CORE and GNU, respectively...). Do a check for the GNU name at the very top (line 902ish?) and handle NT_GNU_BUILD_ID's before the rest of that loop body, or dealing with PRPSINFO logic will get much messier... https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1005,73 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(const lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNote(const lldb::addr_t address, kevinfrei wrote: I'd suggest instead, implement support for the Note section in the same fashion as the other ELF components, with a "parse" method and the like (check out ThreadElfCore.h) and integrated it into the top level loop, same as the other Program Header structures. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1005,73 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(const lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNote(const lldb::addr_t address, + const uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + const uint32_t addr_size = GetAddressByteSize(); + const lldb::offset_t ehdr_phoff_offset = ELFOFFSETOF(Ehdr, e_phoff); + const lldb::offset_t ehdr_phentsize_offset = ELFOFFSETOF(Ehdr, e_phentsize); + const lldb::offset_t ehdr_phnum_offset = ELFOFFSETOF(Ehdr, e_phnum); + const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr) +: sizeof(llvm::ELF::Elf64_Ehdr); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = ehdr_phoff_offset; + lldb::offset_t phoff = data.GetAddress(); + + offset = ehdr_phentsize_offset; + lldb::offset_t phentsize = data.GetU16(); + offset = ehdr_phnum_offset; + lldb::offset_t phnum = data.GetU16(); labath wrote: Reuse the existing `ELFHeader` class for this. I.e., read the necessary amount of bytes (you can just always read `sizeof(Elf64_Ehdr)` as that's larger) into a DataExtractor and call `header.Parse(extractor, 0)`. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -271,6 +282,17 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + if (!m_nt_file_entries.empty()) { labath wrote: Any specific reason doing this as a separate pass (and not from inside parsing loop on line 936)? https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1005,73 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(const lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNote(const lldb::addr_t address, + const uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + const uint32_t addr_size = GetAddressByteSize(); + const lldb::offset_t ehdr_phoff_offset = ELFOFFSETOF(Ehdr, e_phoff); + const lldb::offset_t ehdr_phentsize_offset = ELFOFFSETOF(Ehdr, e_phentsize); + const lldb::offset_t ehdr_phnum_offset = ELFOFFSETOF(Ehdr, e_phnum); + const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr) +: sizeof(llvm::ELF::Elf64_Ehdr); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = ehdr_phoff_offset; + lldb::offset_t phoff = data.GetAddress(); + + offset = ehdr_phentsize_offset; + lldb::offset_t phentsize = data.GetU16(); + offset = ehdr_phnum_offset; + lldb::offset_t phnum = data.GetU16(); + + Section_Note note; + const lldb::addr_t ph_addr = address + phoff; + + for (unsigned int i = 0; i < phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * phentsize, buf, phentsize, error); +if (byte_read != phentsize) + break; +offset = 0; +uint32_t p_type = data.GetU32(); +if (p_type != llvm::ELF::PT_NOTE) + continue; +offset = ELFOFFSETOF(Phdr, p_vaddr); +lldb::addr_t p_vaddr = data.GetAddress(); +offset = ELFOFFSETOF(Phdr, p_memsz); +lldb::addr_t p_memsz = data.GetAddress(); + +byte_read = ReadMemory(p_vaddr, buf, p_memsz, error); +if (byte_read != p_memsz) + continue; +offset = 0; +while ( +offset < p_memsz && +data.GetU32(, , sizeof(Section_Note) / sizeof(uint32_t))) { + if (note.namesz == 4 && note.type == type) { +const char *name = data.GetCStr(); +if (name && strcmp("GNU", name) == 0) + return UUID( + llvm::ArrayRef(buf + offset, note.descsz /*byte size*/)); + } + offset += note.namesz + note.descsz; +} labath wrote: And `parseSegment` for this (despite the generic name, this is really for parsing note segments, maybe you could rename it while you're in here). https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -158,6 +165,16 @@ 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 + std::optional FindNote(const lldb::addr_t address, labath wrote: `const` on a value parameter (pointer and reference parameters are of course different) declaration don't actually do anything, and I don't believe we usually use them. If you really want to you can still make them `const` in [the function definition](https://godbolt.org/z/PxM739P84) even if they're not const in the header (though we usually don't do that either). https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1005,73 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(const lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNote(const lldb::addr_t address, labath wrote: Please give this a more specific name (to say what kind of note its searching for and where). An uninformed reader would think this is searching for a note in the core file itself. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -406,6 +406,36 @@ class Process : public std::enable_shared_from_this, lldb::StateType state); } Notifications; + class ProcessMemoryIterator { labath wrote: AFAICT, this isn't necessary anymore. If you think it's useful, you can make it a separate patch. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/labath commented: This looks much better, though, after looking at this closer, I don't think it's necessary to reimplement the elf parsing code. We already have all the necessary data structures for parsing notes in the core file itself, and it looks like it would be fairly easy to reuse them for this purpose as well. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
@@ -983,6 +1005,73 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +bool ProcessElfCore::IsElf(const lldb::addr_t address) { + uint8_t buf[4]; + Status error; + size_t byte_read = ReadMemory(address, buf, 4, error); + if (byte_read != 4) +return false; + return elf::ELFHeader::MagicBytesMatch(buf); +} + +std::optional ProcessElfCore::FindNote(const lldb::addr_t address, + const uint32_t type) { + if (!IsElf(address)) +return std::nullopt; + const uint32_t addr_size = GetAddressByteSize(); + const lldb::offset_t ehdr_phoff_offset = ELFOFFSETOF(Ehdr, e_phoff); + const lldb::offset_t ehdr_phentsize_offset = ELFOFFSETOF(Ehdr, e_phentsize); + const lldb::offset_t ehdr_phnum_offset = ELFOFFSETOF(Ehdr, e_phnum); + const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr) +: sizeof(llvm::ELF::Elf64_Ehdr); + + unsigned char buf[4096]; + Status error; + size_t byte_read = ReadMemory(address, buf, elf_header_size, error); + DataExtractor data(buf, 4096, GetByteOrder(), addr_size); + lldb::offset_t offset = ehdr_phoff_offset; + lldb::offset_t phoff = data.GetAddress(); + + offset = ehdr_phentsize_offset; + lldb::offset_t phentsize = data.GetU16(); + offset = ehdr_phnum_offset; + lldb::offset_t phnum = data.GetU16(); + + Section_Note note; + const lldb::addr_t ph_addr = address + phoff; + + for (unsigned int i = 0; i < phnum; ++i) { +byte_read = ReadMemory(ph_addr + i * phentsize, buf, phentsize, error); +if (byte_read != phentsize) + break; +offset = 0; +uint32_t p_type = data.GetU32(); +if (p_type != llvm::ELF::PT_NOTE) + continue; +offset = ELFOFFSETOF(Phdr, p_vaddr); +lldb::addr_t p_vaddr = data.GetAddress(); +offset = ELFOFFSETOF(Phdr, p_memsz); +lldb::addr_t p_memsz = data.GetAddress(); labath wrote: Similarly, you can use `ELFProgramHeader::Parse` for this bit. https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/labath edited https://github.com/llvm/llvm-project/pull/92492 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: None (GeorgeHuyubo) Changes As we have debuginfod as symbol locator available in lldb now, we want to make full use of it. In case of post mortem debugging, we don't always have the main executable available. However, the .note.gnu.build-id of the main executable(some other modules too), should be available in the core file, as those binaries are loaded in memory and dumped in the core file. We try to iterate through the NT_FILE entries, read and store the gnu build id if possible. This will be very useful as this id is the unique key which is needed for querying the debuginfod server. Test: Build and run lldb. Breakpoint set to https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfod.cpp#L147 Verified after this commit, module_uuid is the correct gnu build id of the main executable which caused the crash(first in the NT_FILE entry) Previous PR: https://github.com/llvm/llvm-project/pull/92078 was mistakenly merged. This PR is re-opening the commit. --- Full diff: https://github.com/llvm/llvm-project/pull/92492.diff 5 Files Affected: - (modified) lldb/include/lldb/Target/Process.h (+50) - (modified) lldb/source/Commands/CommandObjectMemory.cpp (+2-59) - (modified) lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp (+89) - (modified) lldb/source/Plugins/Process/elf-core/ProcessElfCore.h (+17) - (modified) lldb/source/Target/Process.cpp (+27) ``diff diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index aac0cf51680a9..c8a49edc5c78d 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -406,6 +406,36 @@ class Process : public std::enable_shared_from_this, lldb::StateType state); } Notifications; + class ProcessMemoryIterator { + public: +ProcessMemoryIterator(lldb::ProcessSP process_sp, lldb::addr_t base) +: m_process_sp(process_sp), m_base_addr(base) { + lldbassert(process_sp.get() != nullptr); +} + +bool IsValid() { return m_is_valid; } + +uint8_t operator[](lldb::addr_t offset) { + if (!IsValid()) +return 0; + + uint8_t retval = 0; + Status error; + if (0 == + m_process_sp->ReadMemory(m_base_addr + offset, , 1, error)) { +m_is_valid = false; +return 0; + } + + return retval; +} + + private: +lldb::ProcessSP m_process_sp; +lldb::addr_t m_base_addr; +bool m_is_valid = true; + }; + class ProcessEventData : public EventData { friend class Process; @@ -1649,6 +1679,26 @@ class Process : public std::enable_shared_from_this, lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status ); + /// Find a string within a memory region. + /// + /// This function searches for the string represented by the provided buffer + /// within the memory range specified by the low and high addresses. It uses + /// a bad character heuristic to optimize the search process. + /// + /// \param[in] low The starting address of the memory region to be searched. + /// + /// \param[in] high The ending address of the memory region to be searched. + /// + /// \param[in] buffer A pointer to the buffer containing the string to be + /// searched. + /// + /// \param[in] buffer_size The size of the buffer in bytes. + /// + /// \return The address where the string was found or LLDB_INVALID_ADDRESS if + /// not found. + lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high, +uint8_t *buffer, size_t buffer_size); + bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value, Status ); diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index b78a0492cca55..1c13484dede64 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -977,35 +977,6 @@ class CommandObjectMemoryFind : public CommandObjectParsed { Options *GetOptions() override { return _option_group; } protected: - class ProcessMemoryIterator { - public: -ProcessMemoryIterator(ProcessSP process_sp, lldb::addr_t base) -: m_process_sp(process_sp), m_base_addr(base) { - lldbassert(process_sp.get() != nullptr); -} - -bool IsValid() { return m_is_valid; } - -uint8_t operator[](lldb::addr_t offset) { - if (!IsValid()) -return 0; - - uint8_t retval = 0; - Status error; - if (0 == - m_process_sp->ReadMemory(m_base_addr + offset, , 1, error)) { -m_is_valid = false; -return 0; - } - - return retval; -} - - private: -ProcessSP m_process_sp; -lldb::addr_t m_base_addr; -bool m_is_valid = true; - }; void DoExecute(Args , CommandReturnObject ) override { // No need to check "process"
[Lldb-commits] [lldb] Read and store gnu build id from loaded core file (PR #92492)
https://github.com/GeorgeHuyubo created https://github.com/llvm/llvm-project/pull/92492 As we have debuginfod as symbol locator available in lldb now, we want to make full use of it. In case of post mortem debugging, we don't always have the main executable available. However, the .note.gnu.build-id of the main executable(some other modules too), should be available in the core file, as those binaries are loaded in memory and dumped in the core file. We try to iterate through the NT_FILE entries, read and store the gnu build id if possible. This will be very useful as this id is the unique key which is needed for querying the debuginfod server. Test: Build and run lldb. Breakpoint set to https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolLocator/Debuginfod/SymbolLocatorDebuginfod.cpp#L147 Verified after this commit, module_uuid is the correct gnu build id of the main executable which caused the crash(first in the NT_FILE entry) Previous PR: https://github.com/llvm/llvm-project/pull/92078 was mistakenly merged. This PR is re-opening the commit. >From d375cfe76369413c248e59481b4f299fceba6e62 Mon Sep 17 00:00:00 2001 From: George Hu Date: Tue, 14 May 2024 16:18:20 -0700 Subject: [PATCH] Read and store gnu build id from loaded core file --- lldb/include/lldb/Target/Process.h| 50 +++ lldb/source/Commands/CommandObjectMemory.cpp | 61 + .../Process/elf-core/ProcessElfCore.cpp | 89 +++ .../Plugins/Process/elf-core/ProcessElfCore.h | 17 lldb/source/Target/Process.cpp| 27 ++ 5 files changed, 185 insertions(+), 59 deletions(-) diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index aac0cf51680a9..c8a49edc5c78d 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -406,6 +406,36 @@ class Process : public std::enable_shared_from_this, lldb::StateType state); } Notifications; + class ProcessMemoryIterator { + public: +ProcessMemoryIterator(lldb::ProcessSP process_sp, lldb::addr_t base) +: m_process_sp(process_sp), m_base_addr(base) { + lldbassert(process_sp.get() != nullptr); +} + +bool IsValid() { return m_is_valid; } + +uint8_t operator[](lldb::addr_t offset) { + if (!IsValid()) +return 0; + + uint8_t retval = 0; + Status error; + if (0 == + m_process_sp->ReadMemory(m_base_addr + offset, , 1, error)) { +m_is_valid = false; +return 0; + } + + return retval; +} + + private: +lldb::ProcessSP m_process_sp; +lldb::addr_t m_base_addr; +bool m_is_valid = true; + }; + class ProcessEventData : public EventData { friend class Process; @@ -1649,6 +1679,26 @@ class Process : public std::enable_shared_from_this, lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status ); + /// Find a string within a memory region. + /// + /// This function searches for the string represented by the provided buffer + /// within the memory range specified by the low and high addresses. It uses + /// a bad character heuristic to optimize the search process. + /// + /// \param[in] low The starting address of the memory region to be searched. + /// + /// \param[in] high The ending address of the memory region to be searched. + /// + /// \param[in] buffer A pointer to the buffer containing the string to be + /// searched. + /// + /// \param[in] buffer_size The size of the buffer in bytes. + /// + /// \return The address where the string was found or LLDB_INVALID_ADDRESS if + /// not found. + lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high, +uint8_t *buffer, size_t buffer_size); + bool WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value, Status ); diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index b78a0492cca55..1c13484dede64 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -977,35 +977,6 @@ class CommandObjectMemoryFind : public CommandObjectParsed { Options *GetOptions() override { return _option_group; } protected: - class ProcessMemoryIterator { - public: -ProcessMemoryIterator(ProcessSP process_sp, lldb::addr_t base) -: m_process_sp(process_sp), m_base_addr(base) { - lldbassert(process_sp.get() != nullptr); -} - -bool IsValid() { return m_is_valid; } - -uint8_t operator[](lldb::addr_t offset) { - if (!IsValid()) -return 0; - - uint8_t retval = 0; - Status error; - if (0 == - m_process_sp->ReadMemory(m_base_addr + offset, , 1, error)) { -m_is_valid = false; -return 0; - } - - return retval; -} - - private: -ProcessSP m_process_sp; -