[llvm] r214509 - llvm-objdump: implement printing for MachO __compact_unwind info.
Tim Northover
tnorthover at apple.com
Fri Aug 1 06:07:20 PDT 2014
Author: tnorthover
Date: Fri Aug 1 08:07:19 2014
New Revision: 214509
URL: http://llvm.org/viewvc/llvm-project?rev=214509&view=rev
Log:
llvm-objdump: implement printing for MachO __compact_unwind info.
Added:
llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-i386
llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-x86_64
llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-i386.test
llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-x86_64.test
Modified:
llvm/trunk/tools/llvm-objdump/MachODump.cpp
llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp
llvm/trunk/tools/llvm-objdump/llvm-objdump.h
Added: llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-i386
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-i386?rev=214509&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-i386 (added) and llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-i386 Fri Aug 1 08:07:19 2014 differ
Added: llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-x86_64
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-x86_64?rev=214509&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-x86_64 (added) and llvm/trunk/test/tools/llvm-objdump/Inputs/compact-unwind.macho-x86_64 Fri Aug 1 08:07:19 2014 differ
Added: llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-i386.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-i386.test?rev=214509&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-i386.test (added)
+++ llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-i386.test Fri Aug 1 08:07:19 2014
@@ -0,0 +1,27 @@
+# RUN: llvm-objdump -unwind-info %p/Inputs/compact-unwind.macho-i386 | FileCheck %s
+
+# CHECK: Contents of __compact_unwind section:
+# CHECK: Entry at offset 0x0:
+# CHECK: start: 0x0 __Z10test_throwv
+# CHECK: length: 0x55
+# CHECK: compact encoding: 0x01010005
+# CHECK-NOT: personality function
+# CHECK-NOT: LSDA
+# CHECK: Entry at offset 0x14:
+# CHECK: start: 0x60 __Z11test_catch1v
+# CHECK: length: 0x6f
+# CHECK: compact encoding: 0x41000000
+# CHECK: personality function: 0x288 __pointers + 0x8
+# CHECK: LSDA: 0x180 GCC_except_table1
+# CHECK: Entry at offset 0x28:
+# CHECK: start: 0xd0 __Z11test_catch2v
+# CHECK: length: 0x75
+# CHECK: compact encoding: 0x41000000
+# CHECK: personality function: 0x288 __pointers + 0x8
+# CHECK: LSDA: 0x1a8 GCC_except_table2
+# CHECK: Entry at offset 0x3c:
+# CHECK: start: 0x150 __Z3foov
+# CHECK: length: 0x22
+# CHECK: compact encoding: 0x01000000
+# CHECK-NOT: personality function
+# CHECK-NOT: LSDA
Added: llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-x86_64.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-x86_64.test?rev=214509&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-x86_64.test (added)
+++ llvm/trunk/test/tools/llvm-objdump/macho-compact-unwind-x86_64.test Fri Aug 1 08:07:19 2014
@@ -0,0 +1,27 @@
+# RUN: llvm-objdump -unwind-info %p/Inputs/compact-unwind.macho-x86_64 | FileCheck %s
+
+# CHECK: Contents of __compact_unwind section:
+# CHECK: Entry at offset 0x0:
+# CHECK: start: 0x1 __Z10test_throwv + 0x1
+# CHECK: length: 0x44
+# CHECK: compact encoding: 0x01000000
+# CHECK-NOT: personality function
+# CHECK-NOT: LSDA
+# CHECK: Entry at offset 0x20:
+# CHECK: start: 0x50 __Z11test_catch1v
+# CHECK: length: 0x71
+# CHECK: compact encoding: 0x41000000
+# CHECK: personality function: 0x0 ___gxx_personality_v0
+# CHECK: LSDA: 0x180 GCC_except_table1
+# CHECK: Entry at offset 0x40:
+# CHECK: start: 0xd0 __Z11test_catch2v
+# CHECK: length: 0x77
+# CHECK: compact encoding: 0x41000000
+# CHECK: personality function: 0x0 ___gxx_personality_v0
+# CHECK: LSDA: 0x1a8 GCC_except_table2
+# CHECK: Entry at offset 0x60:
+# CHECK: start: 0x150 __Z3foov
+# CHECK: length: 0x25
+# CHECK: compact encoding: 0x01000000
+# CHECK-NOT: personality function
+# CHECK-NOT: LSDA
Modified: llvm/trunk/tools/llvm-objdump/MachODump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/MachODump.cpp?rev=214509&r1=214508&r2=214509&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objdump/MachODump.cpp (original)
+++ llvm/trunk/tools/llvm-objdump/MachODump.cpp Fri Aug 1 08:07:19 2014
@@ -30,6 +30,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/MachO.h"
@@ -460,3 +461,225 @@ static void DisassembleInputMachO2(Strin
}
}
}
+
+namespace {
+struct CompactUnwindEntry {
+ uint32_t OffsetInSection;
+
+ uint64_t FunctionAddr;
+ uint32_t Length;
+ uint32_t CompactEncoding;
+ uint64_t PersonalityAddr;
+ uint64_t LSDAAddr;
+
+ RelocationRef FunctionReloc;
+ RelocationRef PersonalityReloc;
+ RelocationRef LSDAReloc;
+
+ CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)
+ : OffsetInSection(Offset) {
+ if (Is64)
+ read<uint64_t>(Contents.data() + Offset);
+ else
+ read<uint32_t>(Contents.data() + Offset);
+ }
+
+private:
+ template<typename T>
+ static uint64_t readNext(const char *&Buf) {
+ using llvm::support::little;
+ using llvm::support::unaligned;
+
+ uint64_t Val = support::endian::read<T, little, unaligned>(Buf);
+ Buf += sizeof(T);
+ return Val;
+ }
+
+ template<typename UIntPtr>
+ void read(const char *Buf) {
+ FunctionAddr = readNext<UIntPtr>(Buf);
+ Length = readNext<uint32_t>(Buf);
+ CompactEncoding = readNext<uint32_t>(Buf);
+ PersonalityAddr = readNext<UIntPtr>(Buf);
+ LSDAAddr = readNext<UIntPtr>(Buf);
+ }
+};
+}
+
+/// Given a relocation from __compact_unwind, consisting of the RelocationRef
+/// and data being relocated, determine the best base Name and Addend to use for
+/// display purposes.
+///
+/// 1. An Extern relocation will directly reference a symbol (and the data is
+/// then already an addend), so use that.
+/// 2. Otherwise the data is an offset in the object file's layout; try to find
+// a symbol before it in the same section, and use the offset from there.
+/// 3. Finally, if all that fails, fall back to an offset from the start of the
+/// referenced section.
+static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
+ std::map<uint64_t, SymbolRef> &Symbols,
+ const RelocationRef &Reloc,
+ uint64_t Addr,
+ StringRef &Name, uint64_t &Addend) {
+ if (Reloc.getSymbol() != Obj->symbol_end()) {
+ Reloc.getSymbol()->getName(Name);
+ Addend = Addr;
+ return;
+ }
+
+ auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
+ SectionRef RelocSection = Obj->getRelocationSection(RE);
+
+ uint64_t SectionAddr;
+ RelocSection.getAddress(SectionAddr);
+
+ auto Sym = Symbols.upper_bound(Addr);
+ if (Sym == Symbols.begin()) {
+ // The first symbol in the object is after this reference, the best we can
+ // do is section-relative notation.
+ RelocSection.getName(Name);
+ Addend = Addr - SectionAddr;
+ return;
+ }
+
+ // Go back one so that SymbolAddress <= Addr.
+ --Sym;
+
+ section_iterator SymSection = Obj->section_end();
+ Sym->second.getSection(SymSection);
+ if (RelocSection == *SymSection) {
+ // There's a valid symbol in the same section before this reference.
+ Sym->second.getName(Name);
+ Addend = Addr - Sym->first;
+ return;
+ }
+
+ // There is a symbol before this reference, but it's in a different
+ // section. Probably not helpful to mention it, so use the section name.
+ RelocSection.getName(Name);
+ Addend = Addr - SectionAddr;
+}
+
+static void printUnwindRelocDest(const MachOObjectFile *Obj,
+ std::map<uint64_t, SymbolRef> &Symbols,
+ const RelocationRef &Reloc,
+ uint64_t Addr) {
+ StringRef Name;
+ uint64_t Addend;
+
+ findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);
+
+ outs() << Name;
+ if (Addend)
+ outs() << " + " << format("0x%x", Addend);
+}
+
+static void
+printMachOCompactUnwindSection(const MachOObjectFile *Obj,
+ std::map<uint64_t, SymbolRef> &Symbols,
+ const SectionRef &CompactUnwind) {
+
+ assert(Obj->isLittleEndian() &&
+ "There should not be a big-endian .o with __compact_unwind");
+
+ bool Is64 = Obj->is64Bit();
+ uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);
+ uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);
+
+ StringRef Contents;
+ CompactUnwind.getContents(Contents);
+
+ SmallVector<CompactUnwindEntry, 4> CompactUnwinds;
+
+ // First populate the initial raw offsets, encodings and so on from the entry.
+ for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {
+ CompactUnwindEntry Entry(Contents.data(), Offset, Is64);
+ CompactUnwinds.push_back(Entry);
+ }
+
+ // Next we need to look at the relocations to find out what objects are
+ // actually being referred to.
+ for (const RelocationRef &Reloc : CompactUnwind.relocations()) {
+ uint64_t RelocAddress;
+ Reloc.getOffset(RelocAddress);
+
+ uint32_t EntryIdx = RelocAddress / EntrySize;
+ uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;
+ CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];
+
+ if (OffsetInEntry == 0)
+ Entry.FunctionReloc = Reloc;
+ else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))
+ Entry.PersonalityReloc = Reloc;
+ else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))
+ Entry.LSDAReloc = Reloc;
+ else
+ llvm_unreachable("Unexpected relocation in __compact_unwind section");
+ }
+
+ // Finally, we're ready to print the data we've gathered.
+ outs() << "Contents of __compact_unwind section:\n";
+ for (auto &Entry : CompactUnwinds) {
+ outs() << " Entry at offset " << format("0x%x", Entry.OffsetInSection)
+ << ":\n";
+
+ // 1. Start of the region this entry applies to.
+ outs() << " start: "
+ << format("0x%x", Entry.FunctionAddr) << ' ';
+ printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc,
+ Entry.FunctionAddr);
+ outs() << '\n';
+
+ // 2. Length of the region this entry applies to.
+ outs() << " length: "
+ << format("0x%x", Entry.Length) << '\n';
+ // 3. The 32-bit compact encoding.
+ outs() << " compact encoding: "
+ << format("0x%08x", Entry.CompactEncoding) << '\n';
+
+ // 4. The personality function, if present.
+ if (Entry.PersonalityReloc.getObjectFile()) {
+ outs() << " personality function: "
+ << format("0x%x", Entry.PersonalityAddr) << ' ';
+ printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,
+ Entry.PersonalityAddr);
+ outs() << '\n';
+ }
+
+ // 5. This entry's language-specific data area.
+ if (Entry.LSDAReloc.getObjectFile()) {
+ outs() << " LSDA: "
+ << format("0x%x", Entry.LSDAAddr) << ' ';
+ printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);
+ outs() << '\n';
+ }
+ }
+}
+
+void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
+ std::map<uint64_t, SymbolRef> Symbols;
+ for (const SymbolRef &SymRef : Obj->symbols()) {
+ // Discard any undefined or absolute symbols. They're not going to take part
+ // in the convenience lookup for unwind info and just take up resources.
+ section_iterator Section = Obj->section_end();
+ SymRef.getSection(Section);
+ if (Section == Obj->section_end())
+ continue;
+
+ uint64_t Addr;
+ SymRef.getAddress(Addr);
+ Symbols.insert(std::make_pair(Addr, SymRef));
+ }
+
+ for (const SectionRef &Section : Obj->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ if (SectName == "__compact_unwind")
+ printMachOCompactUnwindSection(Obj, Symbols, Section);
+ else if (SectName == "__unwind_info")
+ outs() << "llvm-objdump: warning: unhandled __unwind_info section\n";
+ else if (SectName == "__eh_frame")
+ outs() << "llvm-objdump: warning: unhandled __eh_frame section\n";
+
+ }
+}
Modified: llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp?rev=214509&r1=214508&r2=214509&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp (original)
+++ llvm/trunk/tools/llvm-objdump/llvm-objdump.cpp Fri Aug 1 08:07:19 2014
@@ -813,10 +813,12 @@ static void PrintUnwindInfo(const Object
if (const COFFObjectFile *coff = dyn_cast<COFFObjectFile>(o)) {
printCOFFUnwindInfo(coff);
- } else {
+ } else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOUnwindInfo(MachO);
+ else {
// TODO: Extract DWARF dump tool to objdump.
errs() << "This operation is only currently supported "
- "for COFF object files.\n";
+ "for COFF and MachO object files.\n";
return;
}
}
Modified: llvm/trunk/tools/llvm-objdump/llvm-objdump.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/llvm-objdump.h?rev=214509&r1=214508&r2=214509&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objdump/llvm-objdump.h (original)
+++ llvm/trunk/tools/llvm-objdump/llvm-objdump.h Fri Aug 1 08:07:19 2014
@@ -18,6 +18,7 @@
namespace llvm {
namespace object {
class COFFObjectFile;
+ class MachOObjectFile;
class ObjectFile;
class RelocationRef;
}
@@ -31,6 +32,8 @@ bool RelocAddressLess(object::Relocation
void DumpBytes(StringRef bytes);
void DisassembleInputMachO(StringRef Filename);
void printCOFFUnwindInfo(const object::COFFObjectFile* o);
+void printMachOUnwindInfo(const object::MachOObjectFile* o);
+
void printELFFileHeader(const object::ObjectFile *o);
void printCOFFFileHeader(const object::ObjectFile *o);
More information about the llvm-commits
mailing list