[llvm-commits] [PATCH] Teach llvm-objdump to dump Win64 exception tables
Kai
kai at redstar.de
Mon Oct 22 07:36:30 PDT 2012
Hi João!
The split is easy - see the attached files. Regarding the lines length I
have to check the sources again...
Regards
Kai
On 22.10.2012 16:24, João Matos wrote:
> Could you attach the "Win64EH.h" field size-related fixes as a separate
> patch? Ideally those should be in their own commit as they're
> independent from the rest of the patch.
>
> The dumping functionality looks good to me and I've been using them
> locally for a while. There's just some lines in there that are too long
> and should be wrapped as to LLVM coding standards.
>
>
> On Mon, Oct 22, 2012 at 3:09 PM, Kai
> <kai at redstar.de <mailto:kai at redstar.de>> wrote:
>
> Hi!
>
> This patch is an extended version of the patch posted by João Matos
> some time ago. It adds a new option 'unwind-info' to llvm-objdump.
> It is then possible to dump Win64 SEH tables. This is a great
> debugging help if you dig into Win64 exception support. Output example:
>
> Function Table:
> Start Address: main$filt$0
> End Address: main$filt$0 + 0x0015
> Unwind Info Address: $unwind$main$filt$0
> Size of prolog: 6
> Number of Codes: 2
> No frame pointer used
> Unwind Codes:
> 0x06: UOP_AllocSmall 32
> 0x02: UOP_PushNonVol RBP
>
> Please review and commit if it looks good.
>
> Regards
> Kai
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> <mailto:llvm-commits at cs.uiuc.edu>
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>
>
>
> --
> João Matos
>
>
> _______________________________________________
> 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/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp
index 13ea4e3..6dabf72 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -46,6 +46,7 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
+#include "llvm/Support/Win64EH.h"
#include <algorithm>
#include <cctype>
#include <cstring>
@@ -100,6 +101,13 @@ 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) {
@@ -566,6 +574,253 @@ static void PrintSymbolTable(const ObjectFile *o) {
}
}
+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);
+ }
+}
+
+static void 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;
+ }
+ }
+}
+
+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 +836,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 +916,8 @@ int main(int argc, char **argv) {
&& !Relocations
&& !SectionHeaders
&& !SectionContents
- && !SymbolTable) {
+ && !SymbolTable
+ && !::UnwindInfo) {
cl::PrintHelpMessage();
return 2;
}
-------------- 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