diff --git a/llvm/test/tools/llvm-readobj/MachO/eh_frame.yaml b/llvm/test/tools/llvm-readobj/MachO/eh_frame.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/MachO/eh_frame.yaml @@ -0,0 +1,127 @@ +## Verify that llvm-readobj can dump the __eh_frame section +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj --unwind %t | FileCheck %s --allow-empty + +# CHECK: __eh_frame { +# CHECK-NEXT: Segment: __TEXT +# CHECK-NEXT: Name: __eh_frame +# CHECK-NEXT: Address: 0x100003FB8 +# CHECK-NEXT: Size: 0x40 +# CHECK-NEXT: Offset: 0x3FB8 +# CHECK-NEXT: Type: Regular (0x0) +# CHECK-NEXT: Attributes [ (0x0) +# CHECK-NEXT: ] +# CHECK-NEXT: [0x100003fb8] CIE length=20 +# CHECK-NEXT: version: 1 +# CHECK-NEXT: augmentation: zR +# CHECK-NEXT: code_alignment_factor: 1 +# CHECK-NEXT: data_alignment_factor: -8 +# CHECK-NEXT: return_address_register: 16 +# CHECK-EMPTY: +# CHECK-NEXT: Program: +# CHECK-NEXT: DW_CFA_def_cfa: reg7 +8 +# CHECK-NEXT: DW_CFA_offset: reg16 -8 +# CHECK-NEXT: DW_CFA_nop: +# CHECK-NEXT: DW_CFA_nop: +# CHECK-EMPTY: +# CHECK-NEXT: [0x100003fd0] FDE length=36 cie=[0x100003fb8] +# CHECK-NEXT: initial_location: 0x100003f60 +# CHECK-NEXT: address_range: 0xf (end : 0x100003f6f) +# CHECK-EMPTY: +# CHECK-NEXT: Program: +# CHECK-NEXT: DW_CFA_advance_loc: 1 +# CHECK-NEXT: DW_CFA_def_cfa_offset: +16 +# CHECK-NEXT: DW_CFA_offset: reg6 -16 +# CHECK-NEXT: DW_CFA_advance_loc: 3 +# CHECK-NEXT: DW_CFA_def_cfa_register: reg6 +# CHECK-NEXT: DW_CFA_nop: +# CHECK-NEXT: DW_CFA_nop: +# CHECK-NEXT: DW_CFA_nop: +# CHECK-NEXT: DW_CFA_nop: +# CHECK-NEXT: DW_CFA_nop: +# CHECK-NEXT: DW_CFA_nop: +# CHECK-NEXT: DW_CFA_nop: +# CHECK-EMPTY: +# CHECK-NEXT: } + +## Note that the following YAML comes from an executable +## built from this test.c source: +## int main() { return 0; } +## ... linked with: +## clang -Wl,-keep_dwarf_unwind -o test{,.c} +## ... and all load commands after the __TEXT segment manually stripped + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000002 + ncmds: 2 + sizeofcmds: 384 + flags: 0x00200085 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 72 + segname: __PAGEZERO + vmaddr: 0 + vmsize: 4294967296 + fileoff: 0 + filesize: 0 + maxprot: 0 + initprot: 0 + nsects: 0 + flags: 0 + - cmd: LC_SEGMENT_64 + cmdsize: 312 + segname: __TEXT + vmaddr: 4294967296 + vmsize: 16384 + fileoff: 0 + filesize: 16384 + maxprot: 5 + initprot: 5 + nsects: 3 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000100003F60 + size: 15 + offset: 0x00003F60 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: 554889E531C0C745FC000000005DC3 + - sectname: __unwind_info + segname: __TEXT + addr: 0x0000000100003F70 + size: 72 + offset: 0x00003F70 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: 010000001C000000000000001C000000000000001C00000002000000603F00003400000034000000703F00000000000034000000030000000C000100100001000000000000000001 + - sectname: __eh_frame + segname: __TEXT + addr: 0x0000000100003FB8 + size: 64 + offset: 0x00003FB8 + align: 3 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: 1400000000000000017A520001781001100C070890010000240000001C00000088FFFFFFFFFFFFFF0F0000000000000000410E108602430D0600000000000000 +... diff --git a/llvm/tools/llvm-readobj/MachODumper.cpp b/llvm/tools/llvm-readobj/MachODumper.cpp --- a/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/llvm/tools/llvm-readobj/MachODumper.cpp @@ -15,6 +15,10 @@ #include "llvm-readobj.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ScopedPrinter.h" @@ -57,6 +61,10 @@ void printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc); + void printCompactUnwind(const SectionRef &Section) const; + void printUnwindInfo(const SectionRef &Section) const; + void printEHFrame(const SectionRef &Section) const; + void printSectionHeaders(const MachOObjectFile *Obj); const MachOObjectFile *Obj; @@ -662,7 +670,95 @@ } void MachODumper::printUnwindInfo() { - W.startLine() << "UnwindInfo not implemented.\n"; + for (const SectionRef &Section : Obj->sections()) { + StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); + if (Name.equals("__compact_unwind")) { + DictScope H(W, "__compact_unwind"); + printCompactUnwind(Section); + } else if (Name.equals("__unwind_info")) { + DictScope H(W, "__unwind_info"); + printUnwindInfo(Section); + } else if (Name.equals("__eh_frame")) { + DictScope H(W, "__eh_frame"); + printEHFrame(Section); + } + } +} + +void MachODumper::printCompactUnwind(const SectionRef &Section) const { + W.startLine() << "printCompactUnwind not yet implemented.\n"; +} + +void MachODumper::printUnwindInfo(const SectionRef &Section) const { + W.startLine() << "printUnwindInfo not yet implemented.\n"; +} + +void MachODumper::printEHFrame(const SectionRef &Section) const { + MachOSection MOSection; + getSection(Obj, Section.getRawDataRefImpl(), MOSection); + uint64_t Address = MOSection.Address; + DataRefImpl DR = Section.getRawDataRefImpl(); + StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); + StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); + StringRef Data = unwrapOrError(Obj->getFileName(), Section.getContents()); + + W.printString("Segment", SegmentName); + W.printString("Name", Name); + W.printHex("Address", Address); + W.printHex("Size", MOSection.Size); + W.printHex("Offset", MOSection.Offset); + W.printEnum("Type", MOSection.Flags & 0xFF, makeArrayRef(MachOSectionTypes)); + W.printFlags("Attributes", MOSection.Flags >> 8, + makeArrayRef(MachOSectionAttributes)); + W.indent(); + + // Construct DWARFDataExtractor to handle relocations ("PC Begin" fields). + std::unique_ptr DICtx = DWARFContext::create(*Obj, nullptr); + // FIXME: IsLittleEndian & AddressSize + DWARFDataExtractor DE(Data, /*IsLittleEndian=*/true, /*AddressSize=*/8); + DWARFDebugFrame EHFrame(Triple::ArchType(Obj->getArch()), /*IsEH=*/true, + /*EHFrameAddress=*/Address); + if (Error E = EHFrame.parse(DE)) + reportError(std::move(E), Obj->getFileName()); + + for (const dwarf::FrameEntry &Entry : EHFrame) { + if (const dwarf::CIE *CIE = dyn_cast(&Entry)) { + W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n", + Address + CIE->getOffset(), CIE->getLength()); + W.indent(); + + W.printNumber("version", CIE->getVersion()); + W.printString("augmentation", CIE->getAugmentationString()); + W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor()); + W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor()); + W.printNumber("return_address_register", CIE->getReturnAddressRegister()); + } else { + const dwarf::FDE *FDE = cast(&Entry); + W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64 + " cie=[0x%" PRIx64 "]\n", + Address + FDE->getOffset(), FDE->getLength(), + Address + FDE->getLinkedCIE()->getOffset()); + W.indent(); + + W.startLine() << format("initial_location: 0x%" PRIx64 "\n", + FDE->getInitialLocation()); + W.startLine() << format( + "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n", + FDE->getAddressRange(), + FDE->getInitialLocation() + FDE->getAddressRange()); + } + + W.getOStream() << "\n"; + W.startLine() << "Program:\n"; + W.indent(); + Entry.cfis().dump(W.getOStream(), DIDumpOptions(), nullptr, + W.getIndentLevel()); + W.unindent(); + W.unindent(); + W.getOStream() << "\n"; + } + + W.unindent(); } void MachODumper::printStackMap() const {