kwk created this revision.
Herald added subscribers: llvm-commits, lldb-commits, MaskRay, hiraditya,
arichardson, mgorny, emaste.
Herald added a reviewer: espindola.
Herald added projects: LLDB, LLVM.
kwk added reviewers: labath, jankratochvil.
kwk marked an inline comment as done.
kwk updated this revision to Diff 217331.
kwk added a comment.
kwk marked an inline comment as not done.
- Change header comment of minidebuginfo
================
Comment at:
lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/TestMiniDebugInfo.py:1
+""" Testing debugging of a binary with "mixed" dwarf (with/without fission).
"""
+import lldb
----------------
I just saw that this header makes no sense.
If the .symtab section is stripped from the binary it might be that
there's a .gnu_debugdata section which contains a smaller .symtab in
order to provide enough information to create a backtrace with function
names or to set and hit a breakpoint on a function name.
This change looks for a .gnu_debugdata section in the ELF object file.
The .gnu_debugdata section contains a xz-compressed ELF file with a
.symtab section inside. Symbols from that compressed .symtab section
are merged with the main object file's .dynsym symbols (if any).
In addition we always load the .dynsym even if there's a .symtab
section.
For example, the Fedora and RHEL operating systems strip their binaries
but keep a .gnu_debugdata section. While gdb already can read this
section, LLDB until this patch couldn't. To test this patch on a
Fedora or RHEL operating system, try to set a breakpoint on the "help"
symbol in the "zip" binary. Before this patch, only GDB can set this
breakpoint; now LLDB also can do so without installing extra debug
symbols:
lldb /usr/bin/zip -b -o "b help" -o "r" -o "bt" -- -h
The above line runs LLDB in batch mode and on the "/usr/bin/zip -h"
target:
(lldb) target create "/usr/bin/zip"
Current executable set to '/usr/bin/zip' (x86_64).
(lldb) settings set -- target.run-args "-h"
Before the program starts, we set a breakpoint on the "help" symbol:
(lldb) b help
Breakpoint 1: where = zip`help, address = 0x00000000004093b0
Once the program is run and has hit the breakpoint we ask for a
backtrace:
(lldb) r
Process 10073 stopped
* thread #1, name = 'zip', stop reason = breakpoint 1.1
frame #0: 0x00000000004093b0 zip`help
zip`help:
-> 0x4093b0 <+0>: pushq %r12
0x4093b2 <+2>: movq 0x2af5f(%rip), %rsi ; + 4056
0x4093b9 <+9>: movl $0x1, %edi
0x4093be <+14>: xorl %eax, %eax
Process 10073 launched: '/usr/bin/zip' (x86_64)
(lldb) bt
* thread #1, name = 'zip', stop reason = breakpoint 1.1
* frame #0: 0x00000000004093b0 zip`help
frame #1: 0x0000000000403970 zip`main + 3248
frame #2: 0x00007ffff7d8bf33 libc.so.6`__libc_start_main + 243
frame #3: 0x0000000000408cee zip`_start + 46
In addition to supporting minidebuginfo this changes ensures that
yaml2obj doens't generate a .symtab section if there previously wasn't
any "Symbols" entry in the YAML file. Initially I planned to test my
code using LLDB-Lit but then I figured that it is necessary to not only
find a symbol but to make sure that we can also hit a breakpoint on a
symbol. I noticed during the development of this change, that one can
set a breakpoint but not necessarily hit it.
In order to support the .gnu_debugdata section, one has to have LZMA
development headers installed. The CMake section, that controls this
part looks for the LZMA headers and enables .gnu_debugdata support by
default if they are found; otherwise or if explicitly requested, the
minidebuginfo support is disabled.
GDB supports the "mini debuginfo" section .gnu_debugdata since v7.6
(2013).
This is another error fixed by this commit that has nothing to do with
this change in general:
Fixed compile error: no memcpy in std ns
/home/kkleine/llvm/llvm/include/llvm/Support/MathExtras.h:271:8: error: no
member named 'memcpy' in namespace 'std'; did you mean 'wmemcpy'?
std::memcpy(in, &Val, sizeof(Val));
~~~~~^~~~~~
wmemcpy
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D66791
Files:
lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/Makefile
lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/TestMiniDebugInfo.py
lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/main.c
lldb/source/Plugins/ObjectFile/ELF/CMakeLists.txt
lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
llvm/include/llvm/ObjectYAML/ELFYAML.h
llvm/include/llvm/Support/MathExtras.h
llvm/lib/ObjectYAML/ELFEmitter.cpp
llvm/lib/ObjectYAML/ELFYAML.cpp
llvm/tools/obj2yaml/elf2yaml.cpp
Index: llvm/tools/obj2yaml/elf2yaml.cpp
===================================================================
--- llvm/tools/obj2yaml/elf2yaml.cpp
+++ llvm/tools/obj2yaml/elf2yaml.cpp
@@ -192,8 +192,8 @@
return TableOrErr.takeError();
ShndxTable = *TableOrErr;
}
- if (SymTab)
- if (Error E = dumpSymbols(SymTab, Y->Symbols))
+ if (SymTab && Y->Symbols)
+ if (Error E = dumpSymbols(SymTab, *Y->Symbols))
return std::move(E);
if (DynSymTab)
if (Error E = dumpSymbols(DynSymTab, Y->DynamicSymbols))
Index: llvm/lib/ObjectYAML/ELFYAML.cpp
===================================================================
--- llvm/lib/ObjectYAML/ELFYAML.cpp
+++ llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -911,6 +911,7 @@
StringRef MappingTraits<ELFYAML::Symbol>::validate(IO &IO,
ELFYAML::Symbol &Symbol) {
+ (void)IO;
if (Symbol.Index && Symbol.Section.data())
return "Index and Section cannot both be specified for Symbol";
if (Symbol.NameIndex && !Symbol.Name.empty())
Index: llvm/lib/ObjectYAML/ELFEmitter.cpp
===================================================================
--- llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -192,7 +192,12 @@
std::make_unique<ELFYAML::Section>(
ELFYAML::Section::SectionKind::RawContent, /*IsImplicit=*/true));
- std::vector<StringRef> ImplicitSections = {".symtab", ".strtab", ".shstrtab"};
+ std::vector<StringRef> ImplicitSections = {".strtab", ".shstrtab"};
+ // We only generate .symtab ELF section if there was a "Symbols" entry in the
+ // YAML file.
+ if (Doc.HasSymbolsEntryInYAML()) {
+ ImplicitSections.insert(ImplicitSections.begin(), {".symtab"});
+ }
if (!Doc.DynamicSymbols.empty())
ImplicitSections.insert(ImplicitSections.end(), {".dynsym", ".dynstr"});
@@ -478,7 +483,8 @@
ELFYAML::Section *YAMLSec) {
bool IsStatic = STType == SymtabType::Static;
- const auto &Symbols = IsStatic ? Doc.Symbols : Doc.DynamicSymbols;
+ const auto &Symbols =
+ IsStatic && Doc.Symbols ? *Doc.Symbols : Doc.DynamicSymbols;
ELFYAML::RawContentSection *RawSec =
dyn_cast_or_null<ELFYAML::RawContentSection>(YAMLSec);
@@ -1013,14 +1019,15 @@
}
template <class ELFT> bool ELFState<ELFT>::buildSymbolIndexes() {
- return buildSymbolsMap(Doc.Symbols, SymN2I) &&
+ return Doc.Symbols && buildSymbolsMap(*Doc.Symbols, SymN2I) &&
buildSymbolsMap(Doc.DynamicSymbols, DynSymN2I);
}
template <class ELFT> void ELFState<ELFT>::finalizeStrings() {
// Add the regular symbol names to .strtab section.
- for (const ELFYAML::Symbol &Sym : Doc.Symbols)
- DotStrtab.add(dropUniqueSuffix(Sym.Name));
+ if (Doc.Symbols)
+ for (const ELFYAML::Symbol &Sym : *Doc.Symbols)
+ DotStrtab.add(dropUniqueSuffix(Sym.Name));
DotStrtab.finalize();
// Add the dynamic symbol names to .dynstr section.
Index: llvm/include/llvm/Support/MathExtras.h
===================================================================
--- llvm/include/llvm/Support/MathExtras.h
+++ llvm/include/llvm/Support/MathExtras.h
@@ -268,7 +268,7 @@
T reverseBits(T Val) {
unsigned char in[sizeof(Val)];
unsigned char out[sizeof(Val)];
- std::memcpy(in, &Val, sizeof(Val));
+ memcpy(in, &Val, sizeof(Val));
for (unsigned i = 0; i < sizeof(Val); ++i)
out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]];
std::memcpy(&Val, out, sizeof(Val));
Index: llvm/include/llvm/ObjectYAML/ELFYAML.h
===================================================================
--- llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -314,8 +314,10 @@
// cleaner and nicer if we read them from the YAML as a separate
// top-level key, which automatically ensures that invariants like there
// being a single SHT_SYMTAB section are upheld.
- std::vector<Symbol> Symbols;
+ Optional<std::vector<Symbol>> Symbols;
std::vector<Symbol> DynamicSymbols;
+
+ bool HasSymbolsEntryInYAML() const { return Symbols.hasValue(); }
};
} // end namespace ELFYAML
Index: lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
===================================================================
--- lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
+++ lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
@@ -59,6 +59,8 @@
SymbolVendor *
SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp,
lldb_private::Stream *feedback_strm) {
+ (void)feedback_strm;
+
if (!module_sp)
return nullptr;
@@ -67,6 +69,30 @@
if (!obj_file)
return nullptr;
+ std::unique_ptr<SymbolVendorELF> symbol_vendor(
+ new SymbolVendorELF(module_sp));
+ SectionList *module_section_list = module_sp->GetSectionList();
+
+ // 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 =
+ 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 = module_section_list->FindSectionByType(
+ eSectionTypeELFSymbolTable, true);
+ if (module_section_sp)
+ module_section_list->ReplaceSection(module_section_sp->GetID(),
+ symtab_section_sp);
+ else
+ module_section_list->AddSection(symtab_section_sp);
+ }
+ }
+ }
+
lldb_private::UUID uuid = obj_file->GetUUID();
if (!uuid)
return nullptr;
@@ -111,11 +137,9 @@
// have stripped the code sections, etc.
dsym_objfile_sp->SetType(ObjectFile::eTypeDebugInfo);
- SymbolVendorELF *symbol_vendor = new SymbolVendorELF(module_sp);
-
// Get the module unified section list and add our debug sections to
// that.
- SectionList *module_section_list = module_sp->GetSectionList();
+ module_section_list = module_sp->GetSectionList();
SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList();
static const SectionType g_sections[] = {
@@ -141,7 +165,8 @@
}
symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
- return symbol_vendor;
+
+ return symbol_vendor.release();
}
// PluginInterface protocol
Index: lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
===================================================================
--- lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -154,6 +154,13 @@
void RelocateSection(lldb_private::Section *section) override;
+ /// Takes the .gnu_debugdata and returns the decompressed object file that is
+ /// stored within that section.
+ ///
+ /// \returns either the decompressed object file stored within the
+ /// .gnu_debugdata section or \c nullptr if an error occured.
+ std::shared_ptr<ObjectFileELF> GetGnuDebugDataObjectFile();
+
protected:
std::vector<LoadableData>
@@ -383,6 +390,8 @@
lldb_private::UUID &uuid);
bool AnySegmentHasPhysicalAddress();
+
+ std::shared_ptr<ObjectFileELF> m_gnuDebugDataObjectFile;
};
#endif // liblldb_ObjectFileELF_h_
Index: lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
===================================================================
--- lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -12,6 +12,10 @@
#include <cassert>
#include <unordered_map>
+#ifdef LLDB_ENABLE_ELF_MINIDEBUGINFO
+#include <lzma.h>
+#endif // LLDB_ENABLE_ELF_MINIDEBUGINFO
+
#include "lldb/Core/FileSpecList.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
@@ -1844,6 +1848,167 @@
unified_section_list = *m_sections_up;
}
+#ifdef LLDB_ENABLE_ELF_MINIDEBUGINFO
+static std::string lzma_ret_to_string(lzma_ret code) {
+ switch (code) {
+#define X(n) \
+ case n: \
+ return #n;
+ X(LZMA_OK)
+ X(LZMA_STREAM_END)
+ X(LZMA_NO_CHECK)
+ X(LZMA_UNSUPPORTED_CHECK)
+ X(LZMA_GET_CHECK)
+ X(LZMA_MEM_ERROR)
+ X(LZMA_MEMLIMIT_ERROR)
+ X(LZMA_FORMAT_ERROR)
+ X(LZMA_OPTIONS_ERROR)
+ X(LZMA_DATA_ERROR)
+ X(LZMA_BUF_ERROR)
+ X(LZMA_PROG_ERROR)
+#undef X
+ }
+ return "Unknown LZMA return code: " + std::to_string(code);
+}
+
+/// Decompresses the xz-compressed content at \a data_start of size \a
+/// data_size.
+///
+/// \param[in] data_start
+/// Pointer to the start of the data.
+///
+/// \param[in] data_size
+/// Size of the compressed data.
+///
+/// \returns a vector with the decompressed content or an error.
+llvm::Expected<std::vector<uint8_t>> decompressXZ(const uint8_t *data_start,
+ uint64_t data_size) {
+ if (!data_start || data_size == 0) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "address (%p) or size (%lu) of xz-compressed blob cannot be 0",
+ data_start, data_size);
+ }
+ auto opts = lzma_stream_flags{};
+ if (data_size < LZMA_STREAM_HEADER_SIZE) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "size of xz-compressed blob ({0} bytes) is smaller than the "
+ "LZMA_STREAM_HEADER_SIZE ({1} bytes)",
+ data_size, LZMA_STREAM_HEADER_SIZE);
+ }
+
+ // Decode xz footer.
+ auto xzerr = lzma_stream_footer_decode(&opts, data_start + data_size -
+ LZMA_STREAM_HEADER_SIZE);
+ if (xzerr != LZMA_OK) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "lzma_stream_footer_decode()={%s}",
+ lzma_ret_to_string(xzerr).c_str());
+ }
+ if (data_size < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "xz-compressed buffer size ({%lu} bytes) too small (required at "
+ "least {%lu} bytes) ",
+ data_size, (opts.backward_size + LZMA_STREAM_HEADER_SIZE));
+ }
+
+ // Decode xz index.
+ lzma_index *xzindex;
+ uint64_t memlimit(UINT64_MAX);
+ size_t inpos = 0;
+ xzerr = lzma_index_buffer_decode(
+ &xzindex, &memlimit, nullptr,
+ data_start + data_size - LZMA_STREAM_HEADER_SIZE - opts.backward_size,
+ &inpos, data_size);
+ if (xzerr != LZMA_OK) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "lzma_index_buffer_decode()={%s}",
+ lzma_ret_to_string(xzerr).c_str());
+ }
+
+ // Get size of uncompressed file to construct an in-memory buffer of the
+ // same size.
+ const auto uncompressed_file_size = lzma_index_uncompressed_size(xzindex);
+ std::vector<uint8_t> result(uncompressed_file_size);
+ // std::vector<uint8_t> decompressed_buf(uncompressed_file_size);
+ if (result.size() != uncompressed_file_size) {
+ if (xzindex != nullptr) {
+ lzma_index_end(xzindex, nullptr);
+ xzindex = nullptr;
+ }
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "failed to allocate decompression buffer of size {%lu} bytes",
+ uncompressed_file_size);
+ }
+
+ // Deallocate xz index as it is no longer needed.
+ lzma_index_end(xzindex, nullptr);
+
+ // Decompress xz buffer to buffer.
+ inpos = 0;
+ size_t outpos = 0;
+ xzerr = lzma_stream_buffer_decode(&memlimit, 0, nullptr, data_start, &inpos,
+ data_size, result.data(), &outpos,
+ result.size());
+ if (xzerr != LZMA_OK) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "lzma_stream_buffer_decode()={%s}",
+ lzma_ret_to_string(xzerr).c_str());
+ }
+
+ return std::move(result);
+}
+#endif // LLDB_ENABLE_ELF_MINIDEBUGINFO
+
+std::shared_ptr<ObjectFileELF> ObjectFileELF::GetGnuDebugDataObjectFile() {
+ if (m_gnuDebugDataObjectFile != nullptr) {
+ return m_gnuDebugDataObjectFile;
+ }
+
+ SectionSP section =
+ GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata"));
+ if (!section) {
+ return nullptr;
+ }
+
+#ifndef LLDB_ENABLE_ELF_MINIDEBUGINFO
+ GetModule()->ReportWarning(
+ "No LZMA support found for reading .gnu_debugdata section");
+ return nullptr;
+#else
+
+ auto data = DataExtractor();
+ section->GetSectionData(data);
+ auto res = decompressXZ(data.GetDataStart(), data.GetByteSize());
+ if (!res) {
+ GetModule()->ReportWarning(
+ "An error occured while decompression the section %s: %s",
+ section->GetName().AsCString(), Status(res.takeError()).AsCString());
+ return nullptr;
+ }
+
+ // Construct ObjectFileELF object from decompressed buffer
+ DataBufferSP gdd_data_buf(new DataBufferHeap(res->data(), res->size()));
+ auto fspec = GetFileSpec().CopyByAppendingPathComponent(
+ llvm::StringRef("gnu_debugdata"));
+ m_gnuDebugDataObjectFile.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_gnuDebugDataObjectFile->SetType(ObjectFile::eTypeDebugInfo);
+
+ ArchSpec spec = m_gnuDebugDataObjectFile->GetArchitecture();
+ if (spec && m_gnuDebugDataObjectFile->SetModulesArchitecture(spec)) {
+ return m_gnuDebugDataObjectFile;
+ }
+
+ return nullptr;
+#endif // LLDB_ENABLE_ELF_MINIDEBUGINFO
+}
+
// Find the arm/aarch64 mapping symbol character in the given symbol name.
// Mapping symbols have the form of "$<char>[.<any>]*". Additionally we
// recognize cases when the mapping symbol prefixed by an arbitrary string
@@ -2649,19 +2814,25 @@
// 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, so if it
+ // doesn't exist then use the dynsym section which should always be
+ // there. If both, .symtab and .dynsym exist, we load both.
+ auto dynsym =
+ section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true)
+ .get();
+ if (dynsym) {
+ if (!m_symtab_up) {
+ auto sec = symtab ? symtab : dynsym;
+ m_symtab_up.reset(new Symtab(sec->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
Index: lldb/source/Plugins/ObjectFile/ELF/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ObjectFile/ELF/CMakeLists.txt
+++ lldb/source/Plugins/ObjectFile/ELF/CMakeLists.txt
@@ -1,3 +1,17 @@
+include(CMakeDependentOption)
+set(minidebuginfo_libs)
+find_package(LibLZMA)
+cmake_dependent_option(LLDB_ENABLE_ELF_LZMA "Compile LLDB with LZMA" ON "LIBLZMA_FOUND" OFF)
+if (LLDB_ENABLE_ELF_LZMA)
+ if (LIBLZMA_FOUND)
+ add_definitions(-DLLDB_ENABLE_ELF_MINIDEBUGINFO)
+ set(minidebuginfo_libs ${LIBLZMA_LIBRARIES})
+ include_directories(${LIBLZMA_INCLUDE_DIRS})
+ else()
+ message(FATAL_ERROR "LZMA is required when LLDB_ENABLE_ELF_LZMA is On.")
+ endif()
+endif()
+
add_lldb_library(lldbPluginObjectFileELF PLUGIN
ELFHeader.cpp
ObjectFileELF.cpp
@@ -7,6 +21,7 @@
lldbHost
lldbSymbol
lldbTarget
+ ${minidebuginfo_libs}
LINK_COMPONENTS
BinaryFormat
Object
Index: lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/main.c
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/main.c
@@ -0,0 +1,6 @@
+int multiplyByThree(int num) { return num * 3; }
+
+int main(int argc, char *argv[]) {
+ (void)argv;
+ return multiplyByThree(argc);
+}
Index: lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/TestMiniDebugInfo.py
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/TestMiniDebugInfo.py
@@ -0,0 +1,36 @@
+""" Testing debugging of a binary with "mini debuginfo" in .gnu_debugdata section. """
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestMinidebugInfo(TestBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ def setUp(self):
+ TestBase.setUp(self)
+
+ @no_debug_info_test # Prevent the genaration of the dwarf version of this test
+ @add_test_categories(["dwo"])
+ @skipUnlessPlatform(["linux"])
+ def test_mini_debug_info(self):
+ """Test that we can set and hit a breakpoint on a symbol from .gnu_debugdata."""
+
+ self.build()
+ exe = self.getBuildArtifact("binary")
+
+ self.target = self.dbg.CreateTarget(exe)
+ self.assertTrue(self.target, VALID_TARGET)
+
+ main_bp = self.target.BreakpointCreateByName("multiplyByThree", "binary")
+ self.assertTrue(main_bp, VALID_BREAKPOINT)
+
+ self.process = self.target.LaunchSimple(
+ None, None, self.get_process_working_directory())
+ self.assertTrue(self.process, PROCESS_IS_VALID)
+
+ # The stop reason of the thread should be breakpoint.
+ self.assertTrue(self.process.GetState() == lldb.eStateStopped,
+ STOPPED_DUE_TO_BREAKPOINT)
+
Index: lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/Makefile
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/linux/minidebuginfo/Makefile
@@ -0,0 +1,52 @@
+LEVEL = ../../make
+C_SOURCES := main.c
+
+all: clean binary
+
+.PHONY: binary
+binary: a.out
+ $(RM) -r $@
+ cp a.out binary
+
+ # Extract the dynamic symbols from the main binary, there is no need
+ # to also have these in the normal symbol table.
+ llvm-nm -D binary --format=posix --defined-only \
+ | awk '{ print $$1 }' | sort > dynsyms
+
+ # Extract all the text (i.e. function) symbols from the debuginfo.
+ # (Note that we actually also accept "D" symbols, for the benefit
+ # of platforms like PowerPC64 that use function descriptors.)
+ llvm-nm binary --format=posix --defined-only \
+ | awk '{ if ($$2 == "T" || $$2 == "t" || $$2 == "D") print $$1 }' \
+ | sort > funcsyms
+
+ # Keep all the function symbols not already in the dynamic symbol
+ # table.
+ comm -13 dynsyms funcsyms > keep_symbols
+
+ # Separate full debug info into debug binary.
+ $(OBJCOPY) --only-keep-debug binary debug
+
+ # Copy the full debuginfo, keeping only a minimal set of symbols and
+ # removing some unnecessary sections.
+ $(OBJCOPY) -S --remove-section .gdb_index --remove-section .comment \
+ --keep-symbols=keep_symbols debug mini_debuginfo
+
+ # Drop the full debug info from the original binary.
+ llvm-strip --strip-all -R .comment binary
+
+ # Inject the compressed data into the .gnu_debugdata section of the
+ # original binary.
+ xz --keep mini_debuginfo
+ $(OBJCOPY) --add-section .gnu_debugdata=mini_debuginfo.xz binary
+
+clean::
+ $(RM) -r mini_debuginfo \
+ mini_debuginfo.xz \
+ binary \
+ debug \
+ keep_symbols \
+ funcsyms \
+ dynsyms
+
+include $(LEVEL)/Makefile.rules
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits