summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp')
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp91
1 files changed, 83 insertions, 8 deletions
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index e507f0e4d74..64e32e5aa41 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -18,6 +18,7 @@
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/LZMA.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/SectionLoadList.h"
@@ -1842,6 +1843,70 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) {
// unified section list.
if (GetType() != eTypeDebugInfo)
unified_section_list = *m_sections_up;
+
+ // If there's a .gnu_debugdata section, we'll try to read the .symtab that's
+ // embedded in there and replace the one in the original object file (if any).
+ // If there's none in the orignal object file, we add it to it.
+ if (auto gdd_obj_file = GetGnuDebugDataObjectFile()) {
+ if (auto gdd_objfile_section_list = gdd_obj_file->GetSectionList()) {
+ if (SectionSP symtab_section_sp =
+ gdd_objfile_section_list->FindSectionByType(
+ eSectionTypeELFSymbolTable, true)) {
+ SectionSP module_section_sp = unified_section_list.FindSectionByType(
+ eSectionTypeELFSymbolTable, true);
+ if (module_section_sp)
+ unified_section_list.ReplaceSection(module_section_sp->GetID(),
+ symtab_section_sp);
+ else
+ unified_section_list.AddSection(symtab_section_sp);
+ }
+ }
+ }
+}
+
+std::shared_ptr<ObjectFileELF> ObjectFileELF::GetGnuDebugDataObjectFile() {
+ if (m_gnu_debug_data_object_file != nullptr)
+ return m_gnu_debug_data_object_file;
+
+ SectionSP section =
+ GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata"));
+ if (!section)
+ return nullptr;
+
+ if (!lldb_private::lzma::isAvailable()) {
+ GetModule()->ReportWarning(
+ "No LZMA support found for reading .gnu_debugdata section");
+ return nullptr;
+ }
+
+ // Uncompress the data
+ DataExtractor data;
+ section->GetSectionData(data);
+ llvm::SmallVector<uint8_t, 0> uncompressedData;
+ auto err = lldb_private::lzma::uncompress(data.GetData(), uncompressedData);
+ if (err) {
+ GetModule()->ReportWarning(
+ "An error occurred while decompression the section %s: %s",
+ section->GetName().AsCString(), llvm::toString(std::move(err)).c_str());
+ return nullptr;
+ }
+
+ // Construct ObjectFileELF object from decompressed buffer
+ DataBufferSP gdd_data_buf(
+ new DataBufferHeap(uncompressedData.data(), uncompressedData.size()));
+ auto fspec = GetFileSpec().CopyByAppendingPathComponent(
+ llvm::StringRef("gnu_debugdata"));
+ m_gnu_debug_data_object_file.reset(new ObjectFileELF(
+ GetModule(), gdd_data_buf, 0, &fspec, 0, gdd_data_buf->GetByteSize()));
+
+ // This line is essential; otherwise a breakpoint can be set but not hit.
+ m_gnu_debug_data_object_file->SetType(ObjectFile::eTypeDebugInfo);
+
+ ArchSpec spec = m_gnu_debug_data_object_file->GetArchitecture();
+ if (spec && m_gnu_debug_data_object_file->SetModulesArchitecture(spec))
+ return m_gnu_debug_data_object_file;
+
+ return nullptr;
}
// Find the arm/aarch64 mapping symbol character in the given symbol name.
@@ -2649,19 +2714,29 @@ Symtab *ObjectFileELF::GetSymtab() {
// while the reverse is not necessarily true.
Section *symtab =
section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get();
- if (!symtab) {
- // The symtab section is non-allocable and can be stripped, so if it
- // doesn't exist then use the dynsym section which should always be
- // there.
- symtab =
- section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true)
- .get();
- }
if (symtab) {
m_symtab_up.reset(new Symtab(symtab->GetObjectFile()));
symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, symtab);
}
+ // The symtab section is non-allocable and can be stripped, while the
+ // .dynsym section which should always be always be there. To support the
+ // minidebuginfo case we parse .dynsym when there's a .gnu_debuginfo
+ // section, nomatter if .symtab was already parsed or not. This is because
+ // minidebuginfo normally removes the .symtab symbols which have their
+ // matching .dynsym counterparts.
+ if (!symtab ||
+ GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata"))) {
+ Section *dynsym =
+ section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true)
+ .get();
+ if (dynsym) {
+ if (!m_symtab_up)
+ m_symtab_up.reset(new Symtab(dynsym->GetObjectFile()));
+ symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, dynsym);
+ }
+ }
+
// DT_JMPREL
// If present, this entry's d_ptr member holds the address of
// relocation
OpenPOWER on IntegriCloud