Skip to content

Commit 3475b3f

Browse files
authored
Enable LLDB to load large dSYM files. (llvm#164471)
llvm-dsymutil can produce mach-o files where some sections in __DWARF exceed the 4GB barrier and subsequent sections in the dSYM will be inaccessible because the mach-o section_64 structure only has a 32 bit file offset. This patch enables LLDB to load a large dSYM file by figuring out when this happens and properly adjusting the file offset of the LLDB sections. I was unable to add a test as obj2yaml and yaml2obj are broken for mach-o files and they can't convert a yaml file back into a valid mach-o object file. Any suggestions for adding a test would be appreciated.
1 parent 39f08eb commit 3475b3f

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,10 @@ void ObjectFileMachO::ProcessSegmentCommand(
16741674
uint32_t segment_sect_idx;
16751675
const lldb::user_id_t first_segment_sectID = context.NextSectionIdx + 1;
16761676

1677+
// 64 bit mach-o files have sections with 32 bit file offsets. If any section
1678+
// data end will exceed UINT32_MAX, then we need to do some bookkeeping to
1679+
// ensure we can access this data correctly.
1680+
uint64_t section_offset_adjust = 0;
16771681
const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
16781682
for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects;
16791683
++segment_sect_idx) {
@@ -1697,6 +1701,16 @@ void ObjectFileMachO::ProcessSegmentCommand(
16971701
// isn't stored in the abstracted Sections.
16981702
m_mach_sections.push_back(sect64);
16991703

1704+
// Make sure we can load sections in mach-o files where some sections cross
1705+
// a 4GB boundary. llvm::MachO::section_64 have only 32 bit file offsets
1706+
// for the file offset of the section contents, so we need to track and
1707+
// sections that overflow and adjust the offsets accordingly.
1708+
const uint64_t section_file_offset =
1709+
(uint64_t)sect64.offset + section_offset_adjust;
1710+
const uint64_t end_section_offset = (uint64_t)sect64.offset + sect64.size;
1711+
if (end_section_offset >= UINT32_MAX)
1712+
section_offset_adjust += end_section_offset & 0xFFFFFFFF00000000ull;
1713+
17001714
if (add_section) {
17011715
ConstString section_name(
17021716
sect64.sectname, strnlen(sect64.sectname, sizeof(sect64.sectname)));
@@ -1736,13 +1750,13 @@ void ObjectFileMachO::ProcessSegmentCommand(
17361750
}
17371751

17381752
// Grow the section size as needed.
1739-
if (sect64.offset) {
1753+
if (section_file_offset) {
17401754
const lldb::addr_t segment_min_file_offset =
17411755
segment->GetFileOffset();
17421756
const lldb::addr_t segment_max_file_offset =
17431757
segment_min_file_offset + segment->GetFileSize();
17441758

1745-
const lldb::addr_t section_min_file_offset = sect64.offset;
1759+
const lldb::addr_t section_min_file_offset = section_file_offset;
17461760
const lldb::addr_t section_max_file_offset =
17471761
section_min_file_offset + sect64.size;
17481762
const lldb::addr_t new_file_offset =
@@ -1769,10 +1783,10 @@ void ObjectFileMachO::ProcessSegmentCommand(
17691783
// other sections.
17701784
sect64.addr, // File VM address == addresses as they are
17711785
// found in the object file
1772-
sect64.size, // VM size in bytes of this section
1773-
sect64.offset, // Offset to the data for this section in
1786+
sect64.size, // VM size in bytes of this section
1787+
section_file_offset, // Offset to the data for this section in
17741788
// the file
1775-
sect64.offset ? sect64.size : 0, // Size in bytes of
1789+
section_file_offset ? sect64.size : 0, // Size in bytes of
17761790
// this section as
17771791
// found in the file
17781792
sect64.align,
@@ -1792,14 +1806,14 @@ void ObjectFileMachO::ProcessSegmentCommand(
17921806
SectionSP section_sp(new Section(
17931807
segment_sp, module_sp, this, ++context.NextSectionIdx, section_name,
17941808
sect_type, sect64.addr - segment_sp->GetFileAddress(), sect64.size,
1795-
sect64.offset, sect64.offset == 0 ? 0 : sect64.size, sect64.align,
1796-
sect64.flags));
1809+
section_file_offset, section_file_offset == 0 ? 0 : sect64.size,
1810+
sect64.align, sect64.flags));
17971811
// Set the section to be encrypted to match the segment
17981812

17991813
bool section_is_encrypted = false;
18001814
if (!segment_is_encrypted && load_cmd.filesize != 0)
18011815
section_is_encrypted = context.EncryptedRanges.FindEntryThatContains(
1802-
sect64.offset) != nullptr;
1816+
section_file_offset) != nullptr;
18031817

18041818
section_sp->SetIsEncrypted(segment_is_encrypted || section_is_encrypted);
18051819
section_sp->SetPermissions(segment_permissions);
344 Bytes
Binary file not shown.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
RUN: %lldb -b %p/Inputs/section-overflow-binary \
2+
RUN: -o 'script dwarf = lldb.target.module[0].sections[0]' \
3+
RUN: -o 'script section = dwarf.GetSubSectionAtIndex(0)' \
4+
RUN: -o "script print(f'{section.GetName()} file_offset=0x{section.GetFileOffset():016x}')" \
5+
RUN: -o 'script section = dwarf.GetSubSectionAtIndex(1)' \
6+
RUN: -o "script print(f'{section.GetName()} file_offset=0x{section.GetFileOffset():016x}')" \
7+
RUN: -o 'script section = dwarf.GetSubSectionAtIndex(2)' \
8+
RUN: -o "script print(f'{section.GetName()} file_offset=0x{section.GetFileOffset():016x}')" \
9+
RUN: | FileCheck %s
10+
11+
CHECK: __debug_abbrev file_offset=0x00000000fffffff0
12+
CHECK: __debug_info file_offset=0x0000000100000010
13+
CHECK: __debug_line file_offset=0x0000000300000010

0 commit comments

Comments
 (0)