From 3ab0ce0cde91cade8e6d0c04d439dbe3988aa204 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Tue, 4 Mar 2014 04:00:55 +0000 Subject: 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 --- .../Inputs/win64-unwind.exe.coff-x86_64 | Bin 698 -> 0 bytes .../Inputs/win64-unwind.exe.coff-x86_64.exe | Bin 0 -> 2560 bytes .../Inputs/win64-unwind.exe.coff-x86_64.obj | Bin 0 -> 698 bytes test/tools/llvm-objdump/win64-unwind-data.test | 155 ++++++++++++++------- tools/llvm-objdump/COFFDump.cpp | 37 ++++- 5 files changed, 138 insertions(+), 54 deletions(-) delete mode 100644 test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64 create mode 100644 test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.exe create mode 100644 test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.obj diff --git a/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64 b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64 deleted file mode 100644 index 63460e7826..0000000000 Binary files a/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64 and /dev/null differ diff --git a/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.exe b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.exe new file mode 100644 index 0000000000..c701c24fb8 Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.exe differ diff --git a/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.obj b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.obj new file mode 100644 index 0000000000..63460e7826 Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/win64-unwind.exe.coff-x86_64.obj differ diff --git a/test/tools/llvm-objdump/win64-unwind-data.test b/test/tools/llvm-objdump/win64-unwind-data.test index 00ad469079..104d959a2a 100644 --- a/test/tools/llvm-objdump/win64-unwind-data.test +++ b/test/tools/llvm-objdump/win64-unwind-data.test @@ -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 diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index ba5de46b9f..53cedbbdbd 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -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 &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(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 &Rels) { outs() << "Function Table:\n"; outs() << " Start Address: "; printCOFFSymbolAddress(outs(), Rels, @@ -516,10 +538,17 @@ void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { return; ArrayRef 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); } } -- cgit v1.2.3