Skip to content

Commit 8a47d87

Browse files
committed
[dsymutil] Copy eh_frame content into the dSYM companion file.
Copy over the __eh_frame from the binary into the dSYM. This helps kernel developers that are working with only dSYMs (i.e. no binaries) when debugging a core file. This only kicks in when the __eh_frame exists in the linked binary. Most of the time ld64 will remove the section in favor of compact unwind info. When it is emitted, it's generally small enough and should not bloat the dSYM. rdar://69774935 Differential revision: https://reviews.llvm.org/D94460
1 parent f454c9f commit 8a47d87

File tree

4 files changed

+88
-17
lines changed

4 files changed

+88
-17
lines changed
Binary file not shown.
Binary file not shown.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FIXME: Replace otool with llvm-objcopy --dump-section=__TEXT,__eh_frame.
2+
REQUIRES : system-darwin
3+
4+
$ cat eh_frame.cpp
5+
int f1()
6+
{
7+
volatile int i;
8+
return i;
9+
}
10+
11+
int main(int argc, char** argv)
12+
{
13+
return f1();
14+
}
15+
16+
$ clang eh_frame.cpp -g -c -o eh_frame.o
17+
$ ld -no_compact_unwind eh_frame.o -o eh_frame.out
18+
19+
RUN: dsymutil -oso-prepend-path %p/../Inputs %p/../Inputs/private/tmp/eh_frame/eh_frame.out -o %t.dSYM
20+
RUN: dwarfdump --verify %t.dSYM
21+
RUN: otool -s __TEXT __eh_frame %p/../Inputs/private/tmp/eh_frame/eh_frame.out | FileCheck %s
22+
RUN: otool -s __TEXT __eh_frame %t.dSYM/Contents/Resources/DWARF/eh_frame.out | FileCheck %s
23+
24+
CHECK: 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01
25+
CHECK: 10 0c 07 08 90 01 00 00

llvm/tools/dsymutil/MachOUtils.cpp

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -239,27 +239,36 @@ getSection(const object::MachOObjectFile &Obj,
239239
// Transfer \a Segment from \a Obj to the output file. This calls into \a Writer
240240
// to write these load commands directly in the output file at the current
241241
// position.
242+
//
242243
// The function also tries to find a hole in the address map to fit the __DWARF
243244
// segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the
244245
// highest segment address.
246+
//
245247
// When the __LINKEDIT segment is transferred, its offset and size are set resp.
246248
// to \a LinkeditOffset and \a LinkeditSize.
249+
//
250+
// When the eh_frame section is transferred, its offset and size are set resp.
251+
// to \a EHFrameOffset and \a EHFrameSize.
247252
template <typename SegmentTy>
248253
static void transferSegmentAndSections(
249254
const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment,
250255
const object::MachOObjectFile &Obj, MachObjectWriter &Writer,
251-
uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t DwarfSegmentSize,
252-
uint64_t &GapForDwarf, uint64_t &EndAddress) {
256+
uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t EHFrameOffset,
257+
uint64_t EHFrameSize, uint64_t DwarfSegmentSize, uint64_t &GapForDwarf,
258+
uint64_t &EndAddress) {
253259
if (StringRef("__DWARF") == Segment.segname)
254260
return;
255261

256-
Segment.fileoff = Segment.filesize = 0;
257-
258-
if (StringRef("__LINKEDIT") == Segment.segname) {
262+
if (StringRef("__TEXT") == Segment.segname && EHFrameSize > 0) {
263+
Segment.fileoff = EHFrameOffset;
264+
Segment.filesize = EHFrameSize;
265+
} else if (StringRef("__LINKEDIT") == Segment.segname) {
259266
Segment.fileoff = LinkeditOffset;
260267
Segment.filesize = LinkeditSize;
261268
// Resize vmsize by rounding to the page size.
262269
Segment.vmsize = alignTo(LinkeditSize, 0x1000);
270+
} else {
271+
Segment.fileoff = Segment.filesize = 0;
263272
}
264273

265274
// Check if the end address of the last segment and our current
@@ -280,7 +289,12 @@ static void transferSegmentAndSections(
280289
Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment));
281290
for (unsigned i = 0; i < nsects; ++i) {
282291
auto Sect = getSection(Obj, Segment, LCI, i);
283-
Sect.offset = Sect.reloff = Sect.nreloc = 0;
292+
if (StringRef("__eh_frame") == Sect.sectname) {
293+
Sect.offset = EHFrameOffset;
294+
Sect.reloff = Sect.nreloc = 0;
295+
} else {
296+
Sect.offset = Sect.reloff = Sect.nreloc = 0;
297+
}
284298
if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
285299
MachO::swapStruct(Sect);
286300
Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect));
@@ -417,6 +431,27 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
417431
++NumLoadCommands;
418432
}
419433

434+
// If we have a valid eh_frame to copy, do it.
435+
uint64_t EHFrameSize = 0;
436+
StringRef EHFrameData;
437+
for (const object::SectionRef &Section : InputBinary.sections()) {
438+
Expected<StringRef> NameOrErr = Section.getName();
439+
if (!NameOrErr) {
440+
consumeError(NameOrErr.takeError());
441+
continue;
442+
}
443+
StringRef SectionName = *NameOrErr;
444+
SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
445+
if (SectionName == "eh_frame") {
446+
if (Expected<StringRef> ContentsOrErr = Section.getContents()) {
447+
EHFrameData = *ContentsOrErr;
448+
EHFrameSize = Section.getSize();
449+
} else {
450+
consumeError(ContentsOrErr.takeError());
451+
}
452+
}
453+
}
454+
420455
unsigned HeaderSize =
421456
Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
422457
// We will copy every segment that isn't __DWARF.
@@ -496,7 +531,10 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
496531
Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart,
497532
NewStringsSize);
498533

499-
uint64_t DwarfSegmentStart = StringStart + NewStringsSize;
534+
uint64_t EHFrameStart = StringStart + NewStringsSize;
535+
EHFrameStart = alignTo(EHFrameStart, 0x1000);
536+
537+
uint64_t DwarfSegmentStart = EHFrameStart + EHFrameSize;
500538
DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000);
501539

502540
// Write the load commands for the segments and sections we 'import' from
@@ -505,15 +543,15 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
505543
uint64_t GapForDwarf = UINT64_MAX;
506544
for (auto &LCI : InputBinary.load_commands()) {
507545
if (LCI.C.cmd == MachO::LC_SEGMENT)
508-
transferSegmentAndSections(LCI, InputBinary.getSegmentLoadCommand(LCI),
509-
InputBinary, Writer, SymtabStart,
510-
StringStart + NewStringsSize - SymtabStart,
511-
DwarfSegmentSize, GapForDwarf, EndAddress);
546+
transferSegmentAndSections(
547+
LCI, InputBinary.getSegmentLoadCommand(LCI), InputBinary, Writer,
548+
SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,
549+
EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);
512550
else if (LCI.C.cmd == MachO::LC_SEGMENT_64)
513-
transferSegmentAndSections(LCI, InputBinary.getSegment64LoadCommand(LCI),
514-
InputBinary, Writer, SymtabStart,
515-
StringStart + NewStringsSize - SymtabStart,
516-
DwarfSegmentSize, GapForDwarf, EndAddress);
551+
transferSegmentAndSections(
552+
LCI, InputBinary.getSegment64LoadCommand(LCI), InputBinary, Writer,
553+
SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,
554+
EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);
517555
}
518556

519557
uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000);
@@ -554,11 +592,19 @@ bool generateDsymCompanion(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
554592
EntryRef.getString().size() + 1);
555593
}
556594
}
557-
558595
assert(OutFile.tell() == StringStart + NewStringsSize);
559596

597+
// Pad till the EH frame start.
598+
OutFile.write_zeros(EHFrameStart - (StringStart + NewStringsSize));
599+
assert(OutFile.tell() == EHFrameStart);
600+
601+
// Transfer eh_frame.
602+
if (EHFrameSize > 0)
603+
OutFile << EHFrameData;
604+
assert(OutFile.tell() == EHFrameStart + EHFrameSize);
605+
560606
// Pad till the Dwarf segment start.
561-
OutFile.write_zeros(DwarfSegmentStart - (StringStart + NewStringsSize));
607+
OutFile.write_zeros(DwarfSegmentStart - (EHFrameStart + EHFrameSize));
562608
assert(OutFile.tell() == DwarfSegmentStart);
563609

564610
// Emit the Dwarf sections contents.

0 commit comments

Comments
 (0)