| Index: bfd/pei-x86_64.c
|
| diff --git a/bfd/pei-x86_64.c b/bfd/pei-x86_64.c
|
| index fdc6205f5a6d9405a0c5d9dc0be2aaa8628bc241..40ca4a61d52bcfa3bea0b2e82cc743403fe847b2 100644
|
| --- a/bfd/pei-x86_64.c
|
| +++ b/bfd/pei-x86_64.c
|
| @@ -17,7 +17,7 @@
|
| along with this program; if not, write to the Free Software
|
| Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
| MA 02110-1301, USA.
|
| -
|
| +
|
| Written by Kai Tietz, OneVision Software GmbH&CoKg. */
|
|
|
| #include "sysdep.h"
|
| @@ -76,11 +76,15 @@
|
| #define AOUTSZ PEPAOUTSZ
|
| #define PEAOUTHDR PEPAOUTHDR
|
|
|
| -static const char *pex_regs[16] = {
|
| +/* Name of registers according to SEH conventions. */
|
| +
|
| +static const char * const pex_regs[16] = {
|
| "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
|
| "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
|
| };
|
|
|
| +/* Swap in a runtime function. */
|
| +
|
| static void
|
| pex64_get_runtime_function (bfd *abfd, struct pex64_runtime_function *rf,
|
| const void *data)
|
| @@ -90,10 +94,10 @@ pex64_get_runtime_function (bfd *abfd, struct pex64_runtime_function *rf,
|
| rf->rva_BeginAddress = bfd_get_32 (abfd, ex_rf->rva_BeginAddress);
|
| rf->rva_EndAddress = bfd_get_32 (abfd, ex_rf->rva_EndAddress);
|
| rf->rva_UnwindData = bfd_get_32 (abfd, ex_rf->rva_UnwindData);
|
| - rf->isChained = PEX64_IS_RUNTIME_FUNCTION_CHAINED (rf);
|
| - rf->rva_UnwindData = PEX64_GET_UNWINDDATA_UNIFIED_RVA (rf);
|
| }
|
|
|
| +/* Swap in unwind info header. */
|
| +
|
| static void
|
| pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
|
| {
|
| @@ -115,7 +119,15 @@ pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
|
| switch (ui->Flags)
|
| {
|
| case UNW_FLAG_CHAININFO:
|
| - ui->rva_FunctionEntry = bfd_get_32 (abfd, ex_dta);
|
| + ui->rva_BeginAddress = bfd_get_32 (abfd, ex_dta + 0);
|
| + ui->rva_EndAddress = bfd_get_32 (abfd, ex_dta + 4);
|
| + ui->rva_UnwindData = bfd_get_32 (abfd, ex_dta + 8);
|
| + ui->SizeOfBlock += 12;
|
| + return;
|
| + case UNW_FLAG_EHANDLER:
|
| + case UNW_FLAG_UHANDLER:
|
| + case UNW_FLAG_FHANDLER:
|
| + ui->rva_ExceptionHandler = bfd_get_32 (abfd, ex_dta);
|
| ui->SizeOfBlock += 4;
|
| return;
|
| default:
|
| @@ -123,168 +135,158 @@ pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
|
| }
|
| }
|
|
|
| +/* Display unwind codes. */
|
| +
|
| static void
|
| -pex64_xdata_print_uwd_codes (FILE *file, struct pex64_unwind_info *ui,
|
| - bfd_vma pc_addr)
|
| +pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
|
| + struct pex64_unwind_info *ui,
|
| + struct pex64_runtime_function *rf)
|
| {
|
| - bfd_vma i;
|
| - bfd_vma tmp = 0;
|
| - const bfd_byte *insns[256];
|
| - bfd_vma insns_count = 0;
|
| - const bfd_byte *dta = ui->rawUnwindCodes;
|
| + unsigned int i;
|
| + unsigned int tmp; /* At least 32 bits. */
|
| + int save_allowed;
|
|
|
| - if (ui->CountOfCodes == 0 || !dta)
|
| + if (ui->CountOfCodes == 0 || ui->rawUnwindCodes == NULL)
|
| return;
|
|
|
| - /* Sort array ascending. Note: it is stored in reversed order. */
|
| - for (i = 0; i < ui->CountOfCodes; i++)
|
| - {
|
| - const bfd_byte *t;
|
| + /* According to UNWIND_CODE documentation:
|
| + If an FP reg is used, the any unwind code taking an offset must only be
|
| + used after the FP reg is established in the prolog.
|
| + But there are counter examples of that in system dlls... */
|
| + save_allowed = TRUE;
|
| +
|
| + i = 0;
|
|
|
| - t = insns[insns_count++] = &dta[i * 2];
|
| - switch (PEX64_UNWCODE_CODE (t[1]))
|
| + if (ui->Version == 2
|
| + && PEX64_UNWCODE_CODE (ui->rawUnwindCodes[1]) == UWOP_EPILOG)
|
| + {
|
| + /* Display epilog opcode (whose docoding is not fully documented).
|
| + Looks to be designed to speed-up unwinding, as there is no need
|
| + to decode instruction flow if outside an epilog. */
|
| + unsigned int func_size = rf->rva_EndAddress - rf->rva_BeginAddress;
|
| +
|
| + fprintf (file, "\tv2 epilog (length: %02x) at pc+:",
|
| + ui->rawUnwindCodes[0]);
|
| + if (PEX64_UNWCODE_INFO (ui->rawUnwindCodes[1]))
|
| + fprintf (file, " 0x%x", func_size - ui->rawUnwindCodes[0]);
|
| + i++;
|
| + for (; i < ui->CountOfCodes; i++)
|
| {
|
| - case UWOP_PUSH_NONVOL:
|
| - case UWOP_ALLOC_SMALL:
|
| - case UWOP_SET_FPREG:
|
| - case UWOP_PUSH_MACHFRAME:
|
| - break;
|
| - case UWOP_ALLOC_LARGE:
|
| - if (PEX64_UNWCODE_INFO (t[1]) == 0)
|
| - {
|
| - i += 1;
|
| - break;
|
| - }
|
| - else if (PEX64_UNWCODE_INFO (t[1]) == 1)
|
| - {
|
| - i += 2;
|
| - break;
|
| - }
|
| - /* fall through. */
|
| - default:
|
| - fprintf (file, "\t contains unknown code (%u).\n",
|
| - (unsigned int) PEX64_UNWCODE_CODE (t[1]));
|
| - return;
|
| - case UWOP_SAVE_NONVOL:
|
| - case UWOP_SAVE_XMM:
|
| - case UWOP_SAVE_XMM128:
|
| - i++;
|
| - break;
|
| - case UWOP_SAVE_NONVOL_FAR:
|
| - case UWOP_SAVE_XMM_FAR:
|
| - case UWOP_SAVE_XMM128_FAR:
|
| - i += 2;
|
| - break;
|
| + const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
|
| + unsigned int off;
|
| +
|
| + if (PEX64_UNWCODE_CODE (dta[1]) != UWOP_EPILOG)
|
| + break;
|
| + off = dta[0] | (PEX64_UNWCODE_INFO (dta[1]) << 8);
|
| + if (off == 0)
|
| + fprintf (file, " [pad]");
|
| + else
|
| + fprintf (file, " 0x%x", func_size - off);
|
| }
|
| + fputc ('\n', file);
|
| }
|
| - fprintf (file, "\t At pc 0x");
|
| - fprintf_vma (file, pc_addr);
|
| - fprintf (file, " there are the following saves (in logical order).\n");
|
| - for (i = insns_count; i > 0;)
|
| +
|
| + for (; i < ui->CountOfCodes; i++)
|
| {
|
| - --i;
|
| - dta = insns[i];
|
| - fprintf (file, "\t insn ends at pc+0x%02x: ", (unsigned int) dta[0]);
|
| + const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
|
| + unsigned int info = PEX64_UNWCODE_INFO (dta[1]);
|
| + int unexpected = FALSE;
|
| +
|
| + fprintf (file, "\t pc+0x%02x: ", (unsigned int) dta[0]);
|
| switch (PEX64_UNWCODE_CODE (dta[1]))
|
| {
|
| case UWOP_PUSH_NONVOL:
|
| - fprintf (file, "push %s.\n", pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
|
| + fprintf (file, "push %s", pex_regs[info]);
|
| break;
|
| case UWOP_ALLOC_LARGE:
|
| - if (PEX64_UNWCODE_INFO (dta[1]) == 0)
|
| + if (info == 0)
|
| {
|
| - tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
|
| - tmp *= 8;
|
| + tmp = bfd_get_16 (abfd, &dta[2]) * 8;
|
| + i++;
|
| }
|
| else
|
| - tmp = (bfd_vma) (*((unsigned int *)&dta[2]));
|
| - fprintf (file, "save stack region of size 0x");
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file,".\n");
|
| + {
|
| + tmp = bfd_get_32 (abfd, &dta[2]);
|
| + i += 2;
|
| + }
|
| + fprintf (file, "alloc large area: rsp = rsp - 0x%x", tmp);
|
| break;
|
| case UWOP_ALLOC_SMALL:
|
| - tmp = (bfd_vma) PEX64_UNWCODE_INFO (dta[1]);
|
| - tmp += 1;
|
| - tmp *= 8;
|
| - fprintf (file, "save stack region of size 0x");
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file,".\n");
|
| + fprintf (file, "alloc small area: rsp = rsp - 0x%x", (info + 1) * 8);
|
| break;
|
| case UWOP_SET_FPREG:
|
| - tmp = (bfd_vma) PEX64_UNWCODE_INFO (dta[1]);
|
| - tmp *= 16;
|
| - fprintf (file, "FPReg = (FrameReg) + 0x");
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file, ".\n");
|
| + /* According to the documentation, info field is unused. */
|
| + fprintf (file, "FPReg: %s = rsp + 0x%x (info = 0x%x)",
|
| + pex_regs[ui->FrameRegister],
|
| + (unsigned int) ui->FrameOffset * 16, info);
|
| + unexpected = ui->FrameRegister == 0;
|
| + save_allowed = FALSE;
|
| break;
|
| case UWOP_SAVE_NONVOL:
|
| - fprintf (file, "mov %s at 0x",
|
| - pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
|
| - tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
|
| - tmp *= 8;
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file, ".\n");
|
| + tmp = bfd_get_16 (abfd, &dta[2]) * 8;
|
| + i++;
|
| + fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
|
| + unexpected = !save_allowed;
|
| break;
|
| case UWOP_SAVE_NONVOL_FAR:
|
| - fprintf (file, "mov %s at 0x",
|
| - pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
|
| - tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file, ".\n");
|
| + tmp = bfd_get_32 (abfd, &dta[2]);
|
| + i += 2;
|
| + fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
|
| + unexpected = !save_allowed;
|
| break;
|
| case UWOP_SAVE_XMM:
|
| - tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
|
| - tmp *= 8;
|
| - fprintf (file, "mov mm%u at 0x",
|
| - (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file, ".\n");
|
| + if (ui->Version == 1)
|
| + {
|
| + tmp = bfd_get_16 (abfd, &dta[2]) * 8;
|
| + i++;
|
| + fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
|
| + unexpected = !save_allowed;
|
| + }
|
| + else if (ui->Version == 2)
|
| + {
|
| + fprintf (file, "epilog %02x %01x", dta[0], info);
|
| + unexpected = TRUE;
|
| + }
|
| break;
|
| case UWOP_SAVE_XMM_FAR:
|
| - tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
|
| - fprintf (file, "mov mm%u at 0x",
|
| - (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file, ".\n");
|
| + tmp = bfd_get_32 (abfd, &dta[2]) * 8;
|
| + i += 2;
|
| + fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
|
| + unexpected = !save_allowed;
|
| break;
|
| case UWOP_SAVE_XMM128:
|
| - tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
|
| - tmp *= 16;
|
| - fprintf (file, "mov xmm%u at 0x",
|
| - (unsigned int) PEX64_UNWCODE_INFO ( dta[1]));
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file, ".\n");
|
| + tmp = bfd_get_16 (abfd, &dta[2]) * 16;
|
| + i++;
|
| + fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
|
| + unexpected = !save_allowed;
|
| break;
|
| case UWOP_SAVE_XMM128_FAR:
|
| - tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
|
| - fprintf (file, "mov xmm%u at 0x",
|
| - (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
|
| - fprintf_vma (file, tmp);
|
| - fprintf (file, ".\n");
|
| + tmp = bfd_get_32 (abfd, &dta[2]) * 16;
|
| + i += 2;
|
| + fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
|
| + unexpected = !save_allowed;
|
| break;
|
| case UWOP_PUSH_MACHFRAME:
|
| fprintf (file, "interrupt entry (SS, old RSP, EFLAGS, CS, RIP");
|
| - if (PEX64_UNWCODE_INFO (dta[1]) == 0)
|
| - {
|
| - fprintf (file, ")");
|
| - }
|
| - else if (PEX64_UNWCODE_INFO (dta[1]) == 1)
|
| - {
|
| - fprintf (file, ",ErrorCode)");
|
| - }
|
| + if (info == 0)
|
| + fprintf (file, ")");
|
| + else if (info == 1)
|
| + fprintf (file, ",ErrorCode)");
|
| else
|
| - fprintf (file, ", unknown(%u))",
|
| - (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
|
| - fprintf (file,".\n");
|
| + fprintf (file, ", unknown(%u))", info);
|
| break;
|
| default:
|
| - fprintf (file, "unknown code %u.\n",
|
| - (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
|
| - break;
|
| + /* Already caught by the previous scan. */
|
| + abort ();
|
| }
|
| + if (unexpected)
|
| + fprintf (file, " [Unexpected!]");
|
| + fputc ('\n', file);
|
| }
|
| }
|
|
|
| +/* Check wether section SEC_NAME contains the xdata at address ADDR. */
|
| +
|
| static asection *
|
| pex64_get_section_by_rva (bfd *abfd, bfd_vma addr, const char *sec_name)
|
| {
|
| @@ -303,110 +305,126 @@ pex64_get_section_by_rva (bfd *abfd, bfd_vma addr, const char *sec_name)
|
| return section;
|
| }
|
|
|
| +/* Dump xdata at for function RF to FILE. The argument XDATA_SECTION
|
| + designate the bfd section containing the xdata, XDATA is its content,
|
| + and ENDX the size if known (or NULL). */
|
| +
|
| static void
|
| -pex64_dump_xdata (FILE *file, bfd *abfd, bfd_vma addr, bfd_vma pc_addr,
|
| - bfd_vma *endx)
|
| +pex64_dump_xdata (FILE *file, bfd *abfd,
|
| + asection *xdata_section, bfd_byte *xdata, bfd_vma *endx,
|
| + struct pex64_runtime_function *rf)
|
| {
|
| - asection *section = pex64_get_section_by_rva (abfd, addr, ".rdata");
|
| - bfd_vma vsize;
|
| - bfd_byte *data = NULL;
|
| + bfd_vma vaddr;
|
| bfd_vma end_addr;
|
| + bfd_vma addr = rf->rva_UnwindData;
|
| + struct pex64_unwind_info ui;
|
|
|
| - if (!section)
|
| - section = pex64_get_section_by_rva (abfd, addr, ".data");
|
| - if (!section)
|
| - section = pex64_get_section_by_rva (abfd, addr, ".xdata");
|
| - if (!section)
|
| - {
|
| - section = pex64_get_section_by_rva (abfd, addr, ".pdata");
|
| - if (section)
|
| - {
|
| - fprintf (file, "\t Shares information with pdata element at 0x");
|
| - fprintf_vma (file, addr + pe_data (abfd)->pe_opthdr.ImageBase);
|
| - fprintf (file, ".\n");
|
| - }
|
| - }
|
| - if (!section)
|
| - return;
|
| -
|
| - vsize = section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
|
| - addr -= vsize;
|
| + vaddr = xdata_section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
|
| + addr -= vaddr;
|
|
|
| if (endx)
|
| - end_addr = endx[0] - vsize;
|
| + end_addr = endx[0] - vaddr;
|
| else
|
| - end_addr = (section->rawsize != 0 ? section->rawsize : section->size);
|
| -
|
| - if (bfd_malloc_and_get_section (abfd, section, &data))
|
| - {
|
| - struct pex64_unwind_info ui;
|
| + end_addr = (xdata_section->rawsize != 0 ?
|
| + xdata_section->rawsize : xdata_section->size);
|
|
|
| - if (!data)
|
| - return;
|
|
|
| - pex64_get_unwind_info (abfd, &ui, &data[addr]);
|
| + pex64_get_unwind_info (abfd, &ui, &xdata[addr]);
|
|
|
| - if (ui.Version != 1)
|
| + if (ui.Version != 1 && ui.Version != 2)
|
| + {
|
| + unsigned int i;
|
| + fprintf (file, "\tVersion %u (unknown).\n",
|
| + (unsigned int) ui.Version);
|
| + for (i = 0; addr < end_addr; addr += 1, i++)
|
| {
|
| - fprintf (file, "\tVersion %u (unknown).\n", (unsigned int) ui.Version);
|
| - return;
|
| + if ((i & 15) == 0)
|
| + fprintf (file, "\t %03x:", i);
|
| + fprintf (file, " %02x", xdata[addr]);
|
| + if ((i & 15) == 15)
|
| + fprintf (file, "\n");
|
| }
|
| + if ((i & 15) != 0)
|
| + fprintf (file, "\n");
|
| + return;
|
| + }
|
|
|
| - fprintf (file, "\tFlags: ");
|
| - switch (ui.Flags)
|
| - {
|
| - case UNW_FLAG_NHANDLER:
|
| - fprintf (file, "UNW_FLAG_NHANDLER");
|
| - break;
|
| - case UNW_FLAG_EHANDLER:
|
| - fprintf (file, "UNW_FLAG_EHANDLER");
|
| - break;
|
| - case UNW_FLAG_UHANDLER:
|
| - fprintf (file, "UNW_FLAG_UHANDLER");
|
| - break;
|
| - case UNW_FLAG_FHANDLER:
|
| - fprintf (file, "UNW_FLAG_FHANDLER = (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER)");
|
| - break;
|
| - case UNW_FLAG_CHAININFO:
|
| - fprintf (file, "UNW_FLAG_CHAININFO");
|
| - break;
|
| - default:
|
| - fprintf (file, "unknown flags value 0x%x", (unsigned int) ui.Flags);
|
| - break;
|
| - }
|
| + fprintf (file, "\tVersion: %d, Flags: ", ui.Version);
|
| + switch (ui.Flags)
|
| + {
|
| + case UNW_FLAG_NHANDLER:
|
| + fprintf (file, "none");
|
| + break;
|
| + case UNW_FLAG_EHANDLER:
|
| + fprintf (file, "UNW_FLAG_EHANDLER");
|
| + break;
|
| + case UNW_FLAG_UHANDLER:
|
| + fprintf (file, "UNW_FLAG_UHANDLER");
|
| + break;
|
| + case UNW_FLAG_FHANDLER:
|
| + fprintf
|
| + (file, "UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER");
|
| + break;
|
| + case UNW_FLAG_CHAININFO:
|
| + fprintf (file, "UNW_FLAG_CHAININFO");
|
| + break;
|
| + default:
|
| + fprintf (file, "unknown flags value 0x%x", (unsigned int) ui.Flags);
|
| + break;
|
| + }
|
| + fputc ('\n', file);
|
| + fprintf (file, "\tNbr codes: %u, ", (unsigned int) ui.CountOfCodes);
|
| + fprintf (file, "Prologue size: 0x%02x, Frame offset: 0x%x, ",
|
| + (unsigned int) ui.SizeOfPrologue, (unsigned int) ui.FrameOffset);
|
| + fprintf (file, "Frame reg: %s\n",
|
| + ui.FrameRegister == 0 ? "none"
|
| + : pex_regs[(unsigned int) ui.FrameRegister]);
|
| +
|
| + pex64_xdata_print_uwd_codes (file, abfd, &ui, rf);
|
| +
|
| + switch (ui.Flags)
|
| + {
|
| + case UNW_FLAG_EHANDLER:
|
| + case UNW_FLAG_UHANDLER:
|
| + case UNW_FLAG_FHANDLER:
|
| + fprintf (file, "\tHandler: ");
|
| + fprintf_vma (file, (ui.rva_ExceptionHandler
|
| + + pe_data (abfd)->pe_opthdr.ImageBase));
|
| fprintf (file, ".\n");
|
| - if (ui.CountOfCodes != 0)
|
| - fprintf (file, "\tEntry has %u codes.", (unsigned int) ui.CountOfCodes);
|
| - fprintf (file, "\tPrologue size: %u, Frame offset = 0x%x.\n",
|
| - (unsigned int) ui.SizeOfPrologue, (unsigned int) ui.FrameOffset);
|
| - fprintf (file, "\tFrame register is %s.\n",
|
| - ui.FrameRegister == 0 ? "none"
|
| - : pex_regs[(unsigned int) ui.FrameRegister]);
|
| -
|
| - pex64_xdata_print_uwd_codes (file, &ui, pc_addr);
|
| -
|
| - /* Now we need end of this xdata block. */
|
| - addr += ui.SizeOfBlock;
|
| - if (addr < end_addr)
|
| - {
|
| - unsigned int i;
|
| - fprintf (file,"\tUser data:\n");
|
| - for (i = 0; addr < end_addr; addr += 1, i++)
|
| - {
|
| - if ((i & 15) == 0)
|
| - fprintf (file, "\t %03x:", i);
|
| - fprintf (file, " %02x", data[addr]);
|
| - if ((i & 15) == 15)
|
| - fprintf (file, "\n");
|
| - }
|
| - if ((i & 15) != 0)
|
| + break;
|
| + case UNW_FLAG_CHAININFO:
|
| + fprintf (file, "\tChain: start: ");
|
| + fprintf_vma (file, ui.rva_BeginAddress);
|
| + fprintf (file, ", end: ");
|
| + fprintf_vma (file, ui.rva_EndAddress);
|
| + fprintf (file, "\n\t unwind data: ");
|
| + fprintf_vma (file, ui.rva_UnwindData);
|
| + fprintf (file, ".\n");
|
| + break;
|
| + }
|
| +
|
| + /* Now we need end of this xdata block. */
|
| + addr += ui.SizeOfBlock;
|
| + if (addr < end_addr)
|
| + {
|
| + unsigned int i;
|
| + fprintf (file,"\tUser data:\n");
|
| + for (i = 0; addr < end_addr; addr += 1, i++)
|
| + {
|
| + if ((i & 15) == 0)
|
| + fprintf (file, "\t %03x:", i);
|
| + fprintf (file, " %02x", xdata[addr]);
|
| + if ((i & 15) == 15)
|
| fprintf (file, "\n");
|
| - }
|
| + }
|
| + if ((i & 15) != 0)
|
| + fprintf (file, "\n");
|
| }
|
| - if (data != NULL)
|
| - free (data);
|
| }
|
|
|
| +/* Helper function to sort xdata. The entries of xdata are sorted to know
|
| + the size of each entry. */
|
| +
|
| static int
|
| sort_xdata_arr (const void *l, const void *r)
|
| {
|
| @@ -418,71 +436,74 @@ sort_xdata_arr (const void *l, const void *r)
|
| return (*lp < *rp ? -1 : 1);
|
| }
|
|
|
| +/* Display unwind tables for x86-64. */
|
| +
|
| static bfd_boolean
|
| pex64_bfd_print_pdata (bfd *abfd, void *vfile)
|
| {
|
| FILE *file = (FILE *) vfile;
|
| - bfd_byte *data = NULL;
|
| - asection *section = bfd_get_section_by_name (abfd, ".pdata");
|
| - bfd_size_type datasize = 0;
|
| + bfd_byte *pdata = NULL;
|
| + bfd_byte *xdata = NULL;
|
| + asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata");
|
| + asection *xdata_section;
|
| + bfd_vma xdata_base;
|
| bfd_size_type i;
|
| bfd_size_type stop;
|
| bfd_vma prev_beginaddress = 0;
|
| + bfd_vma prev_unwinddata_rva = 0;
|
| + bfd_vma imagebase;
|
| int onaline = PDATA_ROW_SIZE;
|
| int seen_error = 0;
|
| - bfd_vma *xdata_arr;
|
| + bfd_vma *xdata_arr = NULL;
|
| int xdata_arr_cnt;
|
|
|
| - if (section == NULL
|
| - || coff_section_data (abfd, section) == NULL
|
| - || pei_section_data (abfd, section) == NULL)
|
| + /* Sanity checks. */
|
| + if (pdata_section == NULL
|
| + || coff_section_data (abfd, pdata_section) == NULL
|
| + || pei_section_data (abfd, pdata_section) == NULL)
|
| return TRUE;
|
|
|
| - stop = pei_section_data (abfd, section)->virt_size;
|
| + stop = pei_section_data (abfd, pdata_section)->virt_size;
|
| if ((stop % onaline) != 0)
|
| fprintf (file,
|
| _("warning: .pdata section size (%ld) is not a multiple of %d\n"),
|
| (long) stop, onaline);
|
|
|
| + /* Display functions table. */
|
| fprintf (file,
|
| _("\nThe Function Table (interpreted .pdata section contents)\n"));
|
|
|
| fprintf (file, _("vma:\t\t\tBeginAddress\t EndAddress\t UnwindData\n"));
|
|
|
| - datasize = section->size;
|
| - if (datasize == 0)
|
| - return TRUE;
|
| -
|
| - if (!bfd_malloc_and_get_section (abfd, section, &data))
|
| - {
|
| - if (data != NULL)
|
| - free (data);
|
| - return FALSE;
|
| - }
|
| + if (!bfd_malloc_and_get_section (abfd, pdata_section, &pdata))
|
| + goto done;
|
|
|
| + /* Table of xdata entries. */
|
| xdata_arr = (bfd_vma *) xmalloc (sizeof (bfd_vma) * ((stop / onaline) + 1));
|
| xdata_arr_cnt = 0;
|
| - /* Do sanity check of pdata. */
|
| +
|
| + imagebase = pe_data (abfd)->pe_opthdr.ImageBase;
|
| +
|
| for (i = 0; i < stop; i += onaline)
|
| {
|
| struct pex64_runtime_function rf;
|
|
|
| if (i + PDATA_ROW_SIZE > stop)
|
| break;
|
| - pex64_get_runtime_function (abfd, &rf, &data[i]);
|
| + pex64_get_runtime_function (abfd, &rf, &pdata[i]);
|
|
|
| if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
|
| && rf.rva_UnwindData == 0)
|
| /* We are probably into the padding of the section now. */
|
| break;
|
| fputc (' ', file);
|
| - fprintf_vma (file, i + section->vma);
|
| + fprintf_vma (file, i + pdata_section->vma);
|
| fprintf (file, ":\t");
|
| - fprintf_vma (file, rf.rva_BeginAddress);
|
| - fputc (' ', file);
|
| - fprintf_vma (file, rf.rva_EndAddress);
|
| - fputc (' ', file);
|
| - fprintf_vma (file, rf.rva_UnwindData);
|
| + fprintf_vma (file, imagebase + rf.rva_BeginAddress);
|
| + fprintf (file, " ");
|
| + fprintf_vma (file, imagebase + rf.rva_EndAddress);
|
| + fprintf (file, " ");
|
| + fprintf_vma (file, imagebase + rf.rva_UnwindData);
|
| fprintf (file, "\n");
|
| if (i != 0 && rf.rva_BeginAddress <= prev_beginaddress)
|
| {
|
| @@ -507,17 +528,12 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
|
| seen_error = 1;
|
| fprintf (file, " has negative unwind address\n");
|
| }
|
| - if (rf.rva_UnwindData && !rf.isChained)
|
| + if (rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
|
| xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData;
|
| }
|
|
|
| if (seen_error)
|
| - {
|
| - free (data);
|
| - free (xdata_arr);
|
| -
|
| - return TRUE;
|
| - }
|
| + goto done;
|
|
|
| /* Add end of list marker. */
|
| xdata_arr[xdata_arr_cnt++] = ~((bfd_vma) 0);
|
| @@ -527,15 +543,30 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
|
| qsort (xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma),
|
| sort_xdata_arr);
|
|
|
| - /* Do dump of pdata related xdata. */
|
| + /* Find the section containing the unwind data (.xdata). */
|
| + xdata_base = xdata_arr[0];
|
| + xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".rdata");
|
| +
|
| + if (!xdata_section)
|
| + xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".data");
|
| + if (!xdata_section)
|
| + xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".xdata");
|
| + if (!xdata_section)
|
| + xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".pdata");
|
| + if (!xdata_section)
|
| + xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".text");
|
| + if (!xdata_section
|
| + || !bfd_malloc_and_get_section (abfd, xdata_section, &xdata))
|
| + goto done;
|
|
|
| + /* Do dump of pdata related xdata. */
|
| for (i = 0; i < stop; i += onaline)
|
| {
|
| struct pex64_runtime_function rf;
|
|
|
| if (i + PDATA_ROW_SIZE > stop)
|
| break;
|
| - pex64_get_runtime_function (abfd, &rf, &data[i]);
|
| + pex64_get_runtime_function (abfd, &rf, &pdata[i]);
|
|
|
| if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
|
| && rf.rva_UnwindData == 0)
|
| @@ -543,19 +574,50 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
|
| break;
|
| if (i == 0)
|
| fprintf (file, "\nDump of .xdata\n");
|
| +
|
| fputc (' ', file);
|
| - fprintf_vma (file, rf.rva_UnwindData);
|
| - fprintf (file, ":\n");
|
| + fprintf_vma (file, rf.rva_UnwindData + imagebase);
|
| +
|
| + if (prev_unwinddata_rva == rf.rva_UnwindData)
|
| + {
|
| + /* Do not dump again the xdata for the same entry. */
|
| + fprintf (file, " also used for function at ");
|
| + fprintf_vma (file, rf.rva_BeginAddress + imagebase);
|
| + fputc ('\n', file);
|
| + continue;
|
| + }
|
| + else
|
| + prev_unwinddata_rva = rf.rva_UnwindData;
|
|
|
| - rf.rva_BeginAddress += pe_data (abfd)->pe_opthdr.ImageBase;
|
| - rf.rva_EndAddress += pe_data (abfd)->pe_opthdr.ImageBase;
|
| + fprintf (file, " (rva: %08x): ",
|
| + (unsigned int) rf.rva_UnwindData);
|
| + fprintf_vma (file, rf.rva_BeginAddress + imagebase);
|
| + fprintf (file, " - ");
|
| + fprintf_vma (file, rf.rva_EndAddress + imagebase);
|
| + fputc ('\n', file);
|
|
|
| if (rf.rva_UnwindData != 0)
|
| {
|
| - if (rf.isChained)
|
| + if (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
|
| {
|
| - fprintf (file, "\t shares information with pdata element at 0x");
|
| - fprintf_vma (file, rf.rva_UnwindData);
|
| + bfd_vma altent = PEX64_GET_UNWINDDATA_UNIFIED_RVA (&rf);
|
| + bfd_vma pdata_vma = bfd_get_section_vma (abfd, pdata_section);
|
| + struct pex64_runtime_function arf;
|
| +
|
| + fprintf (file, "\t shares information with ");
|
| + altent += imagebase;
|
| +
|
| + if (altent >= pdata_vma
|
| + && (altent + PDATA_ROW_SIZE <= pdata_vma
|
| + + pei_section_data (abfd, pdata_section)->virt_size))
|
| + {
|
| + pex64_get_runtime_function
|
| + (abfd, &arf, &pdata[altent - pdata_vma]);
|
| + fprintf (file, "pdata element at 0x");
|
| + fprintf_vma (file, arf.rva_UnwindData);
|
| + }
|
| + else
|
| + fprintf (file, "unknown pdata element");
|
| fprintf (file, ".\n");
|
| }
|
| else
|
| @@ -576,14 +638,15 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
|
| if (p[0] == ~((bfd_vma) 0))
|
| p = NULL;
|
|
|
| - pex64_dump_xdata (file, abfd, rf.rva_UnwindData,
|
| - rf.rva_BeginAddress, p);
|
| + pex64_dump_xdata (file, abfd, xdata_section, xdata, p, &rf);
|
| }
|
| }
|
| }
|
|
|
| - free (data);
|
| + done:
|
| + free (pdata);
|
| free (xdata_arr);
|
| + free (xdata);
|
|
|
| return TRUE;
|
| }
|
|
|