llvm-objdump: Print x64 unwind info in executable.

The original code does not work correctly on executable files because the
code is written in such a way that only object files are assumed to be given
to llvm-objdump.

Contents of RuntimeFunction are different between executables and objects. In
executables, fields in RuntimeFunction have actual addresses to unwind info
structures. On the other hand, in object files, the fields have zero value,
but instead there are relocations pointing to the fields, so that Linker will
fill them at link-time.

So, when we are reading an object file, we need to use relocation info to
find the location of unwind info. When executable, we should just look at the
values in RuntimeFunction.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202785 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rui Ueyama 2014-03-04 04:00:55 +00:00
parent 7ef591d612
commit 3ab0ce0cde
4 changed files with 138 additions and 54 deletions

View File

@ -1,52 +1,107 @@
// This test checks that the unwind data is dumped by llvm-objdump.
// RUN: llvm-objdump -u %p/Inputs/win64-unwind.exe.coff-x86_64 | FileCheck %s
// RUN: llvm-objdump -u %p/Inputs/win64-unwind.exe.coff-x86_64.obj \
// RUN: | FileCheck -check-prefix=OBJ %s
// RUN: llvm-objdump -u %p/Inputs/win64-unwind.exe.coff-x86_64.exe \
// RUN: | FileCheck -check-prefix=EXE %s
CHECK: Unwind info:
CHECK: Function Table:
CHECK-NEXT: Start Address: func
CHECK-NEXT: End Address: func + 0x001b
CHECK-NEXT: Unwind Info Address: .xdata
CHECK-NEXT: Version: 1
CHECK-NEXT: Flags: 1 UNW_ExceptionHandler
CHECK-NEXT: Size of prolog: 18
CHECK-NEXT: Number of Codes: 8
CHECK-NEXT: Frame register: RBX
CHECK-NEXT: Frame offset: 0
CHECK-NEXT: Unwind Codes:
CHECK-NEXT: 0x12: UOP_SetFPReg
CHECK-NEXT: 0x0f: UOP_PushNonVol RBX
CHECK-NEXT: 0x0e: UOP_SaveXMM128 XMM8 [0x0000]
CHECK-NEXT: 0x09: UOP_SaveNonVol RSI [0x0010]
CHECK-NEXT: 0x04: UOP_AllocSmall 24
CHECK-NEXT: 0x00: UOP_PushMachFrame w/o error code
CHECK: Function Table:
CHECK-NEXT: Start Address: func + 0x0012
CHECK-NEXT: End Address: func + 0x0012
CHECK-NEXT: Unwind Info Address: .xdata + 0x001c
CHECK-NEXT: Version: 1
CHECK-NEXT: Flags: 4 UNW_ChainInfo
CHECK-NEXT: Size of prolog: 0
CHECK-NEXT: Number of Codes: 0
CHECK-NEXT: No frame pointer used
CHECK: Function Table:
CHECK-NEXT: Start Address: smallFunc
CHECK-NEXT: End Address: smallFunc + 0x0001
CHECK-NEXT: Unwind Info Address: .xdata + 0x002c
CHECK-NEXT: Version: 1
CHECK-NEXT: Flags: 0
CHECK-NEXT: Size of prolog: 0
CHECK-NEXT: Number of Codes: 0
CHECK-NEXT: No frame pointer used
CHECK: Function Table:
CHECK-NEXT: Start Address: allocFunc
CHECK-NEXT: End Address: allocFunc + 0x001d
CHECK-NEXT: Unwind Info Address: .xdata + 0x0034
CHECK-NEXT: Version: 1
CHECK-NEXT: Flags: 0
CHECK-NEXT: Size of prolog: 14
CHECK-NEXT: Number of Codes: 6
CHECK-NEXT: No frame pointer used
CHECK-NEXT: Unwind Codes:
CHECK-NEXT: 0x0e: UOP_AllocLarge 8454128
CHECK-NEXT: 0x07: UOP_AllocLarge 8190
CHECK-NEXT: 0x00: UOP_PushMachFrame w/o error code
OBJ: Unwind info:
OBJ: Function Table:
OBJ-NEXT: Start Address: func
OBJ-NEXT: End Address: func + 0x001b
OBJ-NEXT: Unwind Info Address: .xdata
OBJ-NEXT: Version: 1
OBJ-NEXT: Flags: 1 UNW_ExceptionHandler
OBJ-NEXT: Size of prolog: 18
OBJ-NEXT: Number of Codes: 8
OBJ-NEXT: Frame register: RBX
OBJ-NEXT: Frame offset: 0
OBJ-NEXT: Unwind Codes:
OBJ-NEXT: 0x12: UOP_SetFPReg
OBJ-NEXT: 0x0f: UOP_PushNonVol RBX
OBJ-NEXT: 0x0e: UOP_SaveXMM128 XMM8 [0x0000]
OBJ-NEXT: 0x09: UOP_SaveNonVol RSI [0x0010]
OBJ-NEXT: 0x04: UOP_AllocSmall 24
OBJ-NEXT: 0x00: UOP_PushMachFrame w/o error code
OBJ: Function Table:
OBJ-NEXT: Start Address: func + 0x0012
OBJ-NEXT: End Address: func + 0x0012
OBJ-NEXT: Unwind Info Address: .xdata + 0x001c
OBJ-NEXT: Version: 1
OBJ-NEXT: Flags: 4 UNW_ChainInfo
OBJ-NEXT: Size of prolog: 0
OBJ-NEXT: Number of Codes: 0
OBJ-NEXT: No frame pointer used
OBJ: Function Table:
OBJ-NEXT: Start Address: smallFunc
OBJ-NEXT: End Address: smallFunc + 0x0001
OBJ-NEXT: Unwind Info Address: .xdata + 0x002c
OBJ-NEXT: Version: 1
OBJ-NEXT: Flags: 0
OBJ-NEXT: Size of prolog: 0
OBJ-NEXT: Number of Codes: 0
OBJ-NEXT: No frame pointer used
OBJ: Function Table:
OBJ-NEXT: Start Address: allocFunc
OBJ-NEXT: End Address: allocFunc + 0x001d
OBJ-NEXT: Unwind Info Address: .xdata + 0x0034
OBJ-NEXT: Version: 1
OBJ-NEXT: Flags: 0
OBJ-NEXT: Size of prolog: 14
OBJ-NEXT: Number of Codes: 6
OBJ-NEXT: No frame pointer used
OBJ-NEXT: Unwind Codes:
OBJ-NEXT: 0x0e: UOP_AllocLarge 8454128
OBJ-NEXT: 0x07: UOP_AllocLarge 8190
OBJ-NEXT: 0x00: UOP_PushMachFrame w/o error code
EXE: Function Table:
EXE: Start Address: 0x1000
EXE: End Address: 0x101b
EXE: Unwind Info Address: : 0x2000
EXE: Version: 1
EXE: Flags: 1 UNW_ExceptionHandler
EXE: Size of prolog: 18
EXE: Number of Codes: 8
EXE: Frame register: RBX
EXE: Frame offset: 0
EXE: Unwind Codes:
EXE: 0x12: UOP_SetFPReg
EXE: 0x0f: UOP_PushNonVol RBX
EXE: 0x0e: UOP_SaveXMM128 XMM8 [0x0000]
EXE: 0x09: UOP_SaveNonVol RSI [0x0010]
EXE: 0x04: UOP_AllocSmall 24
EXE: 0x00: UOP_PushMachFrame w/o error code
EXE: Function Table:
EXE: Start Address: 0x1012
EXE: End Address: 0x1012
EXE: Unwind Info Address: : 0x201c
EXE: Version: 1
EXE: Flags: 4 UNW_ChainInfo
EXE: Size of prolog: 0
EXE: Number of Codes: 0
EXE: No frame pointer used
EXE: Function Table:
EXE: Start Address: 0x101b
EXE: End Address: 0x101c
EXE: Unwind Info Address: : 0x202c
EXE: Version: 1
EXE: Flags: 0
EXE: Size of prolog: 0
EXE: Number of Codes: 0
EXE: No frame pointer used
EXE: Function Table:
EXE: Start Address: 0x101c
EXE: End Address: 0x1039
EXE: Unwind Info Address: : 0x2034
EXE: Version: 1
EXE: Flags: 0
EXE: Size of prolog: 14
EXE: Number of Codes: 6
EXE: No frame pointer used
EXE: Unwind Codes:
EXE: 0x0e: UOP_AllocLarge 8454128
EXE: 0x07: UOP_AllocLarge 8190
EXE: 0x00: UOP_PushMachFrame w/o error code

View File

@ -453,10 +453,32 @@ static void printWin64EHUnwindInfo(const Win64EH::UnwindInfo *UI) {
outs().flush();
}
/// Prints out the given RuntumeFunction struct for x64, assuming that Obj is
/// pointing to an executable file.
static void printRuntimeFunction(const COFFObjectFile *Obj,
const RuntimeFunction &RF,
uint64_t SectionOffset,
const std::vector<RelocationRef> &Rels) {
const RuntimeFunction &RF) {
if (!RF.StartAddress)
return;
outs() << "Function Table:\n"
<< format(" Start Address: 0x%04x\n", RF.StartAddress)
<< format(" End Address: 0x%04x\n", RF.EndAddress)
<< format(" Unwind Info Address: : 0x%04x\n\n", RF.UnwindInfoOffset);
uintptr_t addr;
if (Obj->getRvaPtr(RF.UnwindInfoOffset, addr))
return;
printWin64EHUnwindInfo(reinterpret_cast<const Win64EH::UnwindInfo *>(addr));
}
/// Prints out the given RuntumeFunction struct for x64, assuming that Obj is
/// pointing to an object file. Unlike executable, fields in RuntumeFunction
/// struct are filled with zeros, but instead there are relocations pointing to
/// them so that the linker will fill targets' RVAs to the fields at link
/// time. This function interprets the relocations to find the data to be used
/// in the resulting executable.
static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
const RuntimeFunction &RF,
uint64_t SectionOffset,
const std::vector<RelocationRef> &Rels) {
outs() << "Function Table:\n";
outs() << " Start Address: ";
printCOFFSymbolAddress(outs(), Rels,
@ -516,10 +538,17 @@ void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
return;
ArrayRef<RuntimeFunction> RFs(RFStart, NumRFs);
bool IsExecutable = Rels.empty();
if (IsExecutable) {
for (const RuntimeFunction &RF : RFs)
printRuntimeFunction(Obj, RF);
return;
}
for (const RuntimeFunction &RF : RFs) {
uint64_t SectionOffset =
std::distance(RFs.begin(), &RF) * sizeof(RuntimeFunction);
printRuntimeFunction(Obj, RF, SectionOffset, Rels);
printRuntimeFunctionRels(Obj, RF, SectionOffset, Rels);
}
}