[llvm-commits] [PATCH] Teach llvm-objdump to dump Win64 exception tables
Kai
kai at redstar.de
Fri Nov 2 06:33:12 PDT 2012
Hi Michael!
Sorry for the long delay. I moved the stuff into a separate translation
unit. The changes are attached.
I am going to place a test into folder test/Other (hopefully it fits
there) but I still have trouble to create some good input. Do you have a
suggestion how to do it?
Regards
Kai
On 22.10.2012 23:47, Michael Spencer wrote:
> This needs tests, and PrintCOFFUnwindInfo and friends should be moved
> into a separate translation unit (COFFDump.cpp).
>
> With that it looks good.
>
> - Michael Spencer
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp
new file mode 100644
index 0000000..9cdc729
--- /dev/null
+++ b/tools/llvm-objdump/COFFDump.cpp
@@ -0,0 +1,287 @@
+//===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the COFF-specific dumper for llvm-objdump.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-objdump.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+#include "llvm/Support/Win64EH.h"
+#include <algorithm>
+#include <cstring>
+using namespace llvm;
+using namespace object;
+
+namespace {
+ using namespace llvm::Win64EH;
+
+ llvm::raw_ostream &writeHexNumber(llvm::raw_ostream &Out,
+ unsigned long long N) {
+ if (N >= 10)
+ Out << "0x";
+ Out.write_hex(N);
+ return Out;
+ }
+
+ StringRef GetCOFFUnwindCodeTypeName(uint8_t Code) {
+ switch(Code) {
+ case UOP_PushNonVol: return "UOP_PushNonVol";
+ case UOP_AllocLarge: return "UOP_AllocLarge";
+ case UOP_AllocSmall: return "UOP_AllocSmall";
+ case UOP_SetFPReg: return "UOP_SetFPReg";
+ case UOP_SaveNonVol: return "UOP_SaveNonVol";
+ case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig";
+ case UOP_SaveXMM128: return "UOP_SaveXMM128";
+ case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big";
+ case UOP_PushMachFrame: return "UOP_PushMachFrame";
+ }
+ }
+
+ StringRef GetCOFFUnwindRegisterName(uint8_t Reg) {
+ switch(Reg) {
+ case 0: return "RAX";
+ case 1: return "RCX";
+ case 2: return "RDX";
+ case 3: return "RBX";
+ case 4: return "RSP";
+ case 5: return "RBP";
+ case 6: return "RSI";
+ case 7: return "RDI";
+ case 8: return "R8";
+ case 9: return "R9";
+ case 10: return "R10";
+ case 11: return "R11";
+ case 12: return "R12";
+ case 13: return "R13";
+ case 14: return "R14";
+ case 15: return "R15";
+ }
+ }
+
+ void PrintCOFFUnwindCode(const UnwindCode* UnwindCodes, unsigned numCodes) {
+ for (unsigned i = 0; i < numCodes; i++) {
+ const UnwindCode& UC = UnwindCodes[i];
+ outs() << format(" 0x%02x: ", unsigned(UC.u.codeOffset))
+ << GetCOFFUnwindCodeTypeName(UC.u.unwindOp);
+ switch (UC.u.unwindOp) {
+ case UOP_PushNonVol:
+ outs() << " " << GetCOFFUnwindRegisterName(UC.u.opInfo);
+ break;
+ case UOP_AllocLarge: {
+ uint64_t size;
+ if (UC.u.opInfo == 0) {
+ size = UnwindCodes[++i].frameOffset;
+ }
+ else {
+ size = UnwindCodes[++i].frameOffset
+ + (((uint64_t) UnwindCodes[++i].frameOffset) << 32);
+ }
+ outs() << " " << size;
+ break;
+ }
+ case UOP_AllocSmall:
+ outs() << " " << ((UC.u.opInfo+1) * 8);
+ break;
+ case UOP_SetFPReg:
+ outs() << " ";
+ break;
+ case UOP_SaveNonVol:
+ outs() << " " << GetCOFFUnwindRegisterName(UC.u.opInfo)
+ << format(" [0x%04x]", 8 * UnwindCodes[++i].frameOffset);
+ break;
+ case UOP_SaveNonVolBig: {
+ uint64_t ofs = UnwindCodes[++i].frameOffset
+ + (((uint64_t) UnwindCodes[++i].frameOffset) << 32);
+ outs() << " " << GetCOFFUnwindRegisterName(UC.u.opInfo)
+ << format(" [0x%08" PRIx64 "]", ofs);
+ break;
+ }
+ case UOP_SaveXMM128:
+ outs() << " XMM" << UC.u.opInfo
+ << format(" [0x%04x]", 16 * UnwindCodes[++i].frameOffset);
+ break;
+ case UOP_SaveXMM128Big: {
+ uint64_t ofs = UnwindCodes[++i].frameOffset
+ + (((uint64_t) UnwindCodes[++i].frameOffset) << 32);
+ outs() << " XMM" << UC.u.opInfo << format(" [0x%08" PRIx64 "]", ofs);
+ break;
+ }
+ case UOP_PushMachFrame:
+ outs() << " " << (UC.u.opInfo ? "w/o" : "w") << " error code";
+ break;
+ }
+ outs() << "\n";
+ }
+ }
+
+ error_code ResolveCOFFRelocation(const COFFObjectFile* o,
+ const SymbolRef& sym,
+ const coff_section*& ResolvedSection,
+ uint64_t& ResolvedAddr) {
+ error_code ec;
+ if (ec = sym.getAddress(ResolvedAddr)) return ec;
+ section_iterator iter(o->begin_sections());
+ if (ec = sym.getSection(iter)) return ec;
+ ResolvedSection = o->getCOFFSection(iter);
+ return object_error::success;
+ }
+
+ error_code GetCOFFUnwindInfo(const COFFObjectFile* o,
+ const std::vector<RelocationRef> Rels,
+ uint64_t offset, ArrayRef<uint8_t>& Contents,
+ uint64_t& addr) {
+ for (std::vector<RelocationRef>::const_iterator R = Rels.begin();
+ R != Rels.end(); R++) {
+ error_code ec;
+ uint64_t ofs;
+ if (ec = R->getOffset(ofs)) return ec;
+ if (ofs == offset) {
+ SymbolRef sym;
+ if (ec = R->getSymbol(sym)) return ec;
+ const coff_section* section;
+ ResolveCOFFRelocation(o, sym, section, addr);
+ if (ec = o->getSectionContents(section, Contents)) return ec;
+ break;
+ }
+ }
+ return object_error::success;
+ }
+
+ error_code GetCOFFSymbol(const std::vector<RelocationRef> Rels,
+ uint64_t offset, StringRef& name) {
+ for (std::vector<RelocationRef>::const_iterator R = Rels.begin();
+ R != Rels.end(); R++) {
+ error_code ec;
+ uint64_t ofs;
+ if (ec = R->getOffset(ofs)) return ec;
+ if (ofs == offset) {
+ SymbolRef sym;
+ if (ec = R->getSymbol(sym)) return ec;
+ if (ec = sym.getName(name)) return ec;
+ break;
+ }
+ }
+ return object_error::success;
+ }
+
+ void PrintCOFFSymbolAddress(llvm::raw_ostream &Out,
+ const std::vector<RelocationRef> Rels,
+ uint64_t offset, uint32_t disp) {
+ StringRef sym;
+ GetCOFFSymbol(Rels, offset, sym);
+ Out << sym;
+ if (disp > 0)
+ Out << format(" + 0x%04x", disp);
+ }
+}
+
+void llvm::PrintCOFFUnwindInfo(const COFFObjectFile* o) {
+ const coff_file_header *header;
+ if (error(o->getHeader(header))) return;
+
+ if (header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) {
+ errs() << "Unsupported image machine type "
+ "(currently only AMD64 is supported).\n";
+ return;
+ }
+
+ const coff_section* pdata = 0;
+
+ error_code ec;
+ for (section_iterator si = o->begin_sections(),
+ se = o->end_sections();
+ si != se; si.increment(ec)) {
+ if (error(ec)) return;
+
+ StringRef Name;
+ if (error(si->getName(Name))) continue;
+
+ if (Name.compare(".pdata") == 0) {
+ pdata = o->getCOFFSection(si);
+ std::vector<RelocationRef> Rels;
+ for (relocation_iterator ri = si->begin_relocations(),
+ re = si->end_relocations();
+ ri != re; ri.increment(ec)) {
+ if (error(ec)) break;
+ Rels.push_back(*ri);
+ }
+
+ // Sort relocations by address.
+ std::sort(Rels.begin(), Rels.end(), RelocAddressLess);
+
+ ArrayRef<uint8_t> Contents;
+ if (error(o->getSectionContents(pdata, Contents))) continue;
+ if (Contents.empty()) continue;
+
+ unsigned i = 0;
+ while ((Contents.size() - i) >= sizeof(RuntimeFunction)) {
+ RuntimeFunction* RF = (RuntimeFunction*)(Contents.data() + i);
+
+ outs() << "Function Table:\n";
+
+ outs() << " Start Address: ";
+ PrintCOFFSymbolAddress(outs(), Rels,
+ i + offsetof(RuntimeFunction, startAddress),
+ RF->startAddress);
+ outs() << "\n";
+
+ outs() << " End Address: ";
+ PrintCOFFSymbolAddress(outs(), Rels,
+ i + offsetof(RuntimeFunction, endAddress),
+ RF->endAddress);
+ outs() << "\n";
+
+ outs() << " Unwind Info Address: ";
+ PrintCOFFSymbolAddress(outs(), Rels,
+ i + offsetof(RuntimeFunction, unwindInfoOffset),
+ RF->unwindInfoOffset);
+ outs() << "\n";
+
+ ArrayRef<uint8_t> XContents;
+ uint64_t UnwindInfoOffset = 0;
+ if (error(GetCOFFUnwindInfo(o, Rels,
+ i + offsetof(RuntimeFunction, unwindInfoOffset),
+ XContents, UnwindInfoOffset))) continue;
+ if (XContents.empty()) continue;
+ if (UnwindInfoOffset > XContents.size()) continue;
+
+ Win64EH::UnwindInfo* UI = (Win64EH::UnwindInfo*)
+ (XContents.data() + UnwindInfoOffset);
+
+ outs() << " Size of prolog: " << (int) UI->prologSize << "\n";
+ outs() << " Number of Codes: " << (int) UI->numCodes << "\n";
+ // Maybe this should move to output of UOP_SetFPReg?
+ if (UI->frameRegister) {
+ outs() << " Frame register: "
+ << GetCOFFUnwindRegisterName(UI->frameRegister) << "\n";
+ outs() << " Frame offset: " << 16 * (int) UI->frameOffset << "\n";
+ }
+ else {
+ outs() << " No frame pointer used\n";
+ }
+
+ if (UI->numCodes)
+ outs() << " Unwind Codes:\n";
+
+ PrintCOFFUnwindCode(&UI->unwindCodes[0], UI->numCodes);
+
+ outs() << "\n\n";
+
+ i += sizeof(RuntimeFunction);
+ }
+ continue;
+ }
+ }
+}
diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp
index 13ea4e3..1028b48 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -100,9 +100,16 @@ MAttrs("mattr",
cl::desc("Target specific attributes"),
cl::value_desc("a1,+a2,-a3,..."));
+static cl::opt<bool>
+UnwindInfo("unwind-info", cl::desc("Display unwind information"));
+
+static cl::alias
+UnwindInfoShort("u", cl::desc("Alias for --unwind-info"),
+ cl::aliasopt(::UnwindInfo));
+
static StringRef ToolName;
-static bool error(error_code ec) {
+bool llvm::error(error_code ec) {
if (!ec) return false;
outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
@@ -161,7 +168,7 @@ void llvm::DumpBytes(StringRef bytes) {
outs() << output;
}
-static bool RelocAddressLess(RelocationRef a, RelocationRef b) {
+bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) {
uint64_t a_addr, b_addr;
if (error(a.getAddress(a_addr))) return false;
if (error(b.getAddress(b_addr))) return false;
@@ -566,6 +573,19 @@ static void PrintSymbolTable(const ObjectFile *o) {
}
}
+static void PrintUnwindInfo(const ObjectFile *o) {
+ outs() << "Unwind info:\n\n";
+
+ if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o)) {
+ PrintCOFFUnwindInfo(coff);
+ } else {
+ // TODO: Extract DWARF dump tool to objdump.
+ errs() << "This operation is only currently supported "
+ "for COFF object files.\n";
+ return;
+ }
+}
+
static void DumpObject(const ObjectFile *o) {
outs() << '\n';
outs() << o->getFileName()
@@ -581,6 +601,8 @@ static void DumpObject(const ObjectFile *o) {
PrintSectionContents(o);
if (SymbolTable)
PrintSymbolTable(o);
+ if (::UnwindInfo)
+ PrintUnwindInfo(o);
}
/// @brief Dump each object file in \a a;
@@ -659,7 +681,8 @@ int main(int argc, char **argv) {
&& !Relocations
&& !SectionHeaders
&& !SectionContents
- && !SymbolTable) {
+ && !SymbolTable
+ && !::UnwindInfo) {
cl::PrintHelpMessage();
return 2;
}
diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h
index aa71b77..bf3d422 100644
--- a/tools/llvm-objdump/llvm-objdump.h
+++ b/tools/llvm-objdump/llvm-objdump.h
@@ -17,12 +17,21 @@
namespace llvm {
+namespace object {
+ class COFFObjectFile;
+ class RelocationRef;
+}
+class error_code;
+
extern cl::opt<std::string> TripleName;
extern cl::opt<std::string> ArchName;
// Various helper functions.
+bool error(error_code ec);
+bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b);
void DumpBytes(StringRef bytes);
void DisassembleInputMachO(StringRef Filename);
+void PrintCOFFUnwindInfo(const object::COFFObjectFile* o);
class StringRefMemoryObject : public MemoryObject {
virtual void anchor();
-------------- next part --------------
diff --git a/include/llvm/Support/Win64EH.h b/include/llvm/Support/Win64EH.h
index 8d74e10..fb8aeae 100644
--- a/include/llvm/Support/Win64EH.h
+++ b/include/llvm/Support/Win64EH.h
@@ -60,9 +60,9 @@ enum {
/// RuntimeFunction - An entry in the table of functions with unwind info.
struct RuntimeFunction {
- uint64_t startAddress;
- uint64_t endAddress;
- uint64_t unwindInfoOffset;
+ uint32_t startAddress;
+ uint32_t endAddress;
+ uint32_t unwindInfoOffset;
};
/// UnwindInfo - An entry in the exception table.
@@ -78,17 +78,17 @@ struct UnwindInfo {
void *getLanguageSpecificData() {
return reinterpret_cast<void *>(&unwindCodes[(numCodes+1) & ~1]);
}
- uint64_t getLanguageSpecificHandlerOffset() {
- return *reinterpret_cast<uint64_t *>(getLanguageSpecificData());
+ uint32_t getLanguageSpecificHandlerOffset() {
+ return *reinterpret_cast<uint32_t *>(getLanguageSpecificData());
}
- void setLanguageSpecificHandlerOffset(uint64_t offset) {
+ void setLanguageSpecificHandlerOffset(uint32_t offset) {
*reinterpret_cast<uint64_t *>(getLanguageSpecificData()) = offset;
}
RuntimeFunction *getChainedFunctionEntry() {
return reinterpret_cast<RuntimeFunction *>(getLanguageSpecificData());
}
void *getExceptionData() {
- return reinterpret_cast<void *>(reinterpret_cast<uint64_t *>(
+ return reinterpret_cast<void *>(reinterpret_cast<uint32_t *>(
getLanguageSpecificData())+1);
}
};
More information about the llvm-commits
mailing list