Skip to content
Merged
11 changes: 11 additions & 0 deletions lldb/include/lldb/Core/Section.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ class SectionList {
/// information.
uint64_t GetDebugInfoSize() const;

// Callback to decide which of two matching sections should be used in the
// merged output.
using MergeCallback =
std::function<lldb::SectionSP(lldb::SectionSP, lldb::SectionSP)>;

// Function that merges two different sections into a new output list. All
// unique sections will be checked for conflict and resolved using the
// supplied merging callback.
static std::shared_ptr<SectionList> Merge(SectionList &lhs, SectionList &rhs,
MergeCallback filter);

protected:
collection m_sections;
};
Expand Down
28 changes: 28 additions & 0 deletions lldb/source/Core/Section.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,34 @@ uint64_t SectionList::GetDebugInfoSize() const {
return debug_info_size;
}

std::shared_ptr<SectionList>
SectionList::Merge(SectionList &lhs, SectionList &rhs, MergeCallback filter) {
std::shared_ptr<SectionList> output_sp = std::make_shared<SectionList>();

// Iterate through all the sections in lhs and see if we have matches in
// the rhs list.
for (const auto &lhs_section : lhs) {
auto rhs_section = rhs.FindSectionByName(lhs_section->GetName());
if (rhs_section) {
assert(lhs_section->GetName() == rhs_section->GetName());
output_sp->AddSection(filter(lhs_section, rhs_section));
} else
output_sp->AddSection(lhs_section);
}

// Now that we've visited all possible duplicates, we can iterate over
// the rhs and take any values not in lhs.
for (const auto &rhs_section : rhs) {
auto lhs_section = lhs.FindSectionByName(rhs_section->GetName());
// Because we already visited everything overlapping between rhs
// and lhs, any section not in lhs is unique and can be output.
if (!lhs_section)
output_sp->AddSection(rhs_section);
}

return output_sp;
}

namespace llvm {
namespace json {

Expand Down
45 changes: 41 additions & 4 deletions lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,42 @@ class ELFRelocation {

RelocUnion reloc;
};

lldb::SectionSP MergeSections(lldb::SectionSP lhs, lldb::SectionSP rhs) {
assert(lhs && rhs);

// We only take the RHS is the LHS is SHT_NOBITS, which would be
// represented as a size of 0. Where we can take the rhs.
if (lhs->GetByteSize() == 0)
return rhs;

lldb::ModuleSP lhs_module_parent = lhs->GetModule();
lldb::ModuleSP rhs_module_parent = rhs->GetModule();
assert(lhs_module_parent && rhs_module_parent);

// Now that we're taking the lhs, we should do some sanity checks to warn the
// user if this debuginfo/dwp looks invalid. However if RHS is SHT_NO_BITS
// we want to ignore the size comparison.
if (rhs->GetByteSize() > 0 && lhs->GetByteSize() != rhs->GetByteSize())
lhs_module_parent->ReportWarning(
"Mismatched size for section {0} when merging with {1}, expected: "
"{2:x}, "
"actual: {3:x}",
lhs->GetTypeAsCString(),
rhs_module_parent->GetFileSpec().GetPathAsConstString().GetCString(),
lhs->GetByteSize(), rhs->GetByteSize());

if (lhs->GetFileAddress() != rhs->GetFileAddress())
lhs_module_parent->ReportWarning(
"Mismatch addresses for section {0} when "
"merging with {1}, expected: {2:x}, "
"actual: {3:x}",
lhs->GetTypeAsCString(),
rhs_module_parent->GetFileSpec().GetPathAsConstString().GetCString(),
lhs->GetByteSize(), rhs->GetByteSize());

return lhs;
}
} // end anonymous namespace

ELFRelocation::ELFRelocation(unsigned type) {
Expand Down Expand Up @@ -1967,10 +2003,11 @@ void ObjectFileELF::CreateSections(SectionList &unified_section_list) {
provider.AddSection(std::move(*InfoOr), std::move(section_sp));
}

// For eTypeDebugInfo files, the Symbol Vendor will take care of updating the
// unified section list.
if (GetType() != eTypeDebugInfo)
unified_section_list = *m_sections_up;
// Merge the two adding any new sections, and overwriting any existing
// sections that are SHT_NOBITS
std::shared_ptr<SectionList> merged_section_list =
SectionList::Merge(unified_section_list, *m_sections_up, MergeSections);
unified_section_list = *merged_section_list;

// 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).
Expand Down
5 changes: 5 additions & 0 deletions lldb/test/API/python_api/unified_section_list/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CXX_SOURCES := main.cpp

SPLIT_DEBUG_SYMBOLS := YES

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Test Unified Section List merging.
"""

import os

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test.lldbutil import symbol_type_to_str


class ModuleUnifiedSectionList(TestBase):
@skipUnlessPlatform(["linux", "freebsd", "netbsd"])
def test_unified_section_list(self):
self.build()
exe = self.getBuildArtifact("a.out")
debug_info = self.getBuildArtifact("a.out.debug")
new_dir = os.path.join(os.path.dirname(debug_info), "new_dir")
os.mkdir(new_dir)
renamed_debug_info = os.path.join(new_dir, "renamed.debug")
os.rename(debug_info, renamed_debug_info)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
self.assertGreater(target.GetNumModules(), 0)

main_exe_module = target.GetModuleAtIndex(0)
eh_frame = main_exe_module.FindSection(".eh_frame")
self.assertTrue(eh_frame.IsValid())
self.assertGreater(eh_frame.size, 0)

# Should be stripped in main executable.
debug_info_section = main_exe_module.FindSection(".debug_info")
self.assertFalse(debug_info_section.IsValid())

ci = self.dbg.GetCommandInterpreter()
res = lldb.SBCommandReturnObject()
ci.HandleCommand(f"target symbols add {renamed_debug_info}", res)
self.assertTrue(res.Succeeded())

# Should be stripped in .debuginfo but be present in main executable.
main_exe_module = target.GetModuleAtIndex(0)
eh_frame = main_exe_module.FindSection(".eh_frame")
self.assertTrue(eh_frame.IsValid())
self.assertGreater(eh_frame.size, 0)

# Should be unified and both sections should have contents.
debug_info_section = main_exe_module.FindSection(".debug_info")
self.assertTrue(debug_info_section.IsValid())
self.assertGreater(debug_info_section.file_size, 0)
3 changes: 3 additions & 0 deletions lldb/test/API/python_api/unified_section_list/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <stdio.h>

int main() { printf("Hello World\n"); }
Loading