static void stab_context (void) { int i; fprintf (stderr, _("Last stabs entries before error:\n")); fprintf (stderr, "n_type n_desc n_value string\n"); i = saved_stabs_index; do { struct saved_stab *stabp; stabp = saved_stabs + i; if (stabp->string != NULL) { const char *s; s = bfd_get_stab_name (stabp->type); if (s != NULL) fprintf (stderr, "%-6s", s); else if (stabp->type == 0) fprintf (stderr, "HdrSym"); else fprintf (stderr, "%-6d", stabp->type); fprintf (stderr, " %-6d ", stabp->desc); fprintf_vma (stderr, stabp->value); if (stabp->type != 0) fprintf (stderr, " %s", stabp->string); fprintf (stderr, "\n"); } i = (i + 1) % SAVE_STABS_COUNT; } while (i != saved_stabs_index); }
void fprint_value (FILE *file, valueT val) { if (sizeof (val) <= sizeof (long)) { fprintf (file, "%ld", (long) val); return; } #ifdef BFD_ASSEMBLER if (sizeof (val) <= sizeof (bfd_vma)) { fprintf_vma (file, val); return; } #endif abort (); }
static bfd_boolean pex64_bfd_print_pdata_section (bfd *abfd, void *vfile, asection *pdata_section) { FILE *file = (FILE *) vfile; bfd_byte *pdata = NULL; bfd_byte *xdata = NULL; asection *xdata_section = NULL; bfd_vma xdata_base; bfd_size_type i; bfd_size_type datasize; bfd_size_type stop; bfd_vma prev_beginaddress = (bfd_vma) -1; bfd_vma prev_unwinddata_rva = (bfd_vma) -1; bfd_vma imagebase; int onaline = PDATA_ROW_SIZE; int seen_error = 0; bfd_vma *xdata_arr = NULL; int xdata_arr_cnt; bfd_boolean virt_size_is_zero = FALSE; /* 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, pdata_section)->virt_size; if ((stop % onaline) != 0) fprintf (file, _("Warning: %s section size (%ld) is not a multiple of %d\n"), pdata_section->name, (long) stop, onaline); datasize = pdata_section->size; if (datasize == 0) { if (stop) fprintf (file, _("Warning: %s section size is zero\n"), pdata_section->name); return TRUE; } /* virt_size might be zero for objects. */ if (stop == 0 && strcmp (abfd->xvec->name, "pe-x86-64") == 0) { stop = (datasize / onaline) * onaline; virt_size_is_zero = TRUE; } else if (datasize < stop) { fprintf (file, _("Warning: %s section size (%ld) is smaller than virtual size (%ld)\n"), pdata_section->name, (unsigned long) datasize, (unsigned long) stop); /* Be sure not to read passed datasize. */ stop = datasize / onaline; } /* Display functions table. */ fprintf (file, _("\nThe Function Table (interpreted %s section contents)\n"), pdata_section->name); fprintf (file, _("vma:\t\t\tBeginAddress\t EndAddress\t UnwindData\n")); 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; if (strcmp (abfd->xvec->name, "pei-x86-64") == 0) imagebase = pe_data (abfd)->pe_opthdr.ImageBase; else imagebase = 0; 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, &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 + pdata_section->vma); fprintf (file, ":\t"); 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) { seen_error = 1; fprintf (file, " has %s begin address as predecessor\n", (rf.rva_BeginAddress < prev_beginaddress ? "smaller" : "same")); } prev_beginaddress = rf.rva_BeginAddress; /* Now we check for negative addresses. */ if ((prev_beginaddress & 0x80000000) != 0) { seen_error = 1; fprintf (file, " has negative begin address\n"); } if ((rf.rva_EndAddress & 0x80000000) != 0) { seen_error = 1; fprintf (file, " has negative end address\n"); } if ((rf.rva_UnwindData & 0x80000000) != 0) { seen_error = 1; fprintf (file, " has negative unwind address\n"); } else if ((rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf)) || virt_size_is_zero) xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData; } if (seen_error) goto done; /* Add end of list marker. */ xdata_arr[xdata_arr_cnt++] = ~((bfd_vma) 0); /* Sort start RVAs of xdata. */ if (xdata_arr_cnt > 1) qsort (xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma), sort_xdata_arr); /* Find the section containing the unwind data (.xdata). */ xdata_base = xdata_arr[0]; /* For sections with long names, first look for the same section name, replacing .pdata by .xdata prefix. */ if (strcmp (pdata_section->name, ".pdata") != 0) { size_t len = strlen (pdata_section->name); char *xdata_name = alloca (len + 1); xdata_name = memcpy (xdata_name, pdata_section->name, len + 1); /* Transform .pdata prefix into .xdata prefix. */ if (len > 1) xdata_name [1] = 'x'; xdata_section = pex64_get_section_by_rva (abfd, xdata_base, xdata_name); } /* Second, try the .xdata section itself. */ if (!xdata_section) xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".xdata"); /* Otherwise, if xdata_base is non zero, search also inside other standard sections. */ if (!xdata_section && xdata_base) xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".rdata"); if (!xdata_section && xdata_base) xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".data"); if (!xdata_section && xdata_base) xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".pdata"); if (!xdata_section && xdata_base) xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".text"); /* Transfer xdata section into xdata array. */ if (!xdata_section || !bfd_malloc_and_get_section (abfd, xdata_section, &xdata)) goto done; /* Avoid "also used "... ouput for single unwind info in object file. */ prev_unwinddata_rva = (bfd_vma) -1; /* 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, &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; if (i == 0) fprintf (file, _("\nDump of %s\n"), xdata_section->name); fputc (' ', file); 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; 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 || virt_size_is_zero) { if (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf)) { 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 { bfd_vma *p; /* Search for the current entry in the sorted array. */ p = (bfd_vma *) bsearch (&rf.rva_UnwindData, xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma), sort_xdata_arr); /* Advance to the next pointer into the xdata section. We may have shared xdata entries, which will result in a string of identical pointers in the array; advance past all of them. */ while (p[0] <= rf.rva_UnwindData) ++p; if (p[0] == ~((bfd_vma) 0)) p = NULL; pex64_dump_xdata (file, abfd, xdata_section, xdata, p, &rf); } } } done: free (pdata); free (xdata_arr); free (xdata); return TRUE; }
static void pex64_dump_xdata (FILE *file, bfd *abfd, asection *xdata_section, bfd_byte *xdata, bfd_vma *endx, struct pex64_runtime_function *rf) { bfd_vma vaddr; bfd_vma end_addr; bfd_vma addr = rf->rva_UnwindData; bfd_size_type sec_size = xdata_section->rawsize > 0 ? xdata_section->rawsize : xdata_section->size; struct pex64_unwind_info ui; vaddr = xdata_section->vma - pe_data (abfd)->pe_opthdr.ImageBase; addr -= vaddr; /* PR 17512: file: 2245-7442-0.004. */ if (addr >= sec_size) { fprintf (file, _("warning: xdata section corrupt\n")); return; } if (endx) { end_addr = endx[0] - vaddr; /* PR 17512: file: 2245-7442-0.004. */ if (end_addr > sec_size) { fprintf (file, _("warning: xdata section corrupt")); end_addr = sec_size; } } else end_addr = sec_size; pex64_get_unwind_info (abfd, &ui, &xdata[addr]); 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++) { 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, "\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]); /* PR 17512: file: 2245-7442-0.004. */ if (ui.CountOfCodes * 2 + ui.rawUnwindCodes > xdata + xdata_section->size) fprintf (file, _("Too many unwind codes (%ld)\n"), (long) ui.CountOfCodes); else 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"); 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"); } }
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_size_type i; bfd_size_type start, stop; int onaline = PDATA_ROW_SIZE; if (section == NULL || coff_section_data (abfd, section) == NULL || pei_section_data (abfd, section) == NULL) return TRUE; stop = pei_section_data (abfd, section)->virt_size; if ((stop % onaline) != 0) fprintf (file, _("warning: .pdata section size (%ld) is not a multiple of %d\n"), (long) stop, onaline); 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; } start = 0; for (i = start; i < stop; i += onaline) { struct pex64_runtime_function rf; if (i + PDATA_ROW_SIZE > stop) break; pex64_get_runtime_function (abfd, &rf, &data[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 (file, ":\t"); rf.rva_BeginAddress += pe_data (abfd)->pe_opthdr.ImageBase; fprintf_vma (file, rf.rva_BeginAddress); fputc (' ', file); rf.rva_EndAddress += pe_data (abfd)->pe_opthdr.ImageBase; fprintf_vma (file, rf.rva_EndAddress); fputc (' ', file); fprintf_vma (file, rf.rva_UnwindData); fprintf (file, "\n"); if (rf.rva_UnwindData != 0) { if (rf.isChained) { fprintf (file, "\t shares information with pdata element at 0x"); fprintf_vma (file, rf.rva_UnwindData + pe_data (abfd)->pe_opthdr.ImageBase); fprintf (file, ".\n"); } else pex64_dump_xdata (file, abfd, rf.rva_UnwindData, rf.rva_BeginAddress); } } free (data); return TRUE; }
static void pex64_dump_xdata (FILE *file, bfd *abfd, bfd_vma addr, bfd_vma pc_addr) { asection *section = pex64_get_section_by_rva (abfd, addr, ".rdata"); bfd_vma vsize; bfd_byte *data = NULL; bfd_vma i; 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; if (bfd_malloc_and_get_section (abfd, section, &data)) { struct pex64_unwind_info ui; if (!data) return; pex64_get_unwind_info (abfd, &ui, &data[addr]); if (ui.Version != 1) { fprintf (file, "\tVersion %u (unknown).\n", (unsigned int) ui.Version); 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, ".\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 ? "CFA" : pex_regs[(unsigned int) ui.FrameRegister]); pex64_xdata_print_uwd_codes (file, &ui, pc_addr); switch (ui.Flags) { case UNW_FLAG_NHANDLER: return; case UNW_FLAG_EHANDLER: fprintf (file, "\texception_handler at 0x%x.\n", (unsigned int) ui.rva_ExceptionHandler); break; case UNW_FLAG_UHANDLER: fprintf (file, "\ttermination_handler at 0x%x.\n", (unsigned int) ui.rva_TerminationHandler); case UNW_FLAG_FHANDLER: fprintf (file, "\tframe_handler at 0x%x.\n", (unsigned int) ui.rva_FrameHandler); fprintf (file, "\t Argument for FrameHandler: 0x%x.\n", (unsigned int) ui.FrameHandlerArgument); return; case UNW_FLAG_CHAININFO: fprintf (file, "\t Function Entry: 0x%x\n", (unsigned int) ui.rva_FunctionEntry); return; default: fprintf (file, "\t Unknown flag value of 0x%x\n", (unsigned int) ui.Flags); return; } fprintf (file, "\t 0x%x # of scope(s)\n", (unsigned int) ui.CountOfScopes); for (i = 0; i < ui.CountOfScopes; i++) { struct pex64_scope_entry se; pex64_get_scope_entry (abfd, &se, i, ui.rawScopeEntries); fprintf (file, "\t scope #%u: BeginAddress: 0x%x, EndAddress: 0x%x," "\n\t\tHandlerAddress:0x%x, JumpTarget:0x%x\n", (unsigned int) (i + 1), (unsigned int) se.rva_BeginAddress, (unsigned int) se.rva_EndAddress, (unsigned int) se.rva_HandlerAddress, (unsigned int) se.rva_JumpAddress); } } if (data != NULL) free (data); }
static void pex64_xdata_print_uwd_codes (FILE *file, struct pex64_unwind_info *ui, bfd_vma pc_addr) { bfd_vma i; bfd_vma tmp = 0; const bfd_byte *insns[256]; bfd_vma insns_count = 0; const bfd_byte *dta = ui->rawUnwindCodes; if (ui->CountOfCodes == 0 || !dta) return; /* Sort array ascending. Note: it is stored in reversed order. */ for (i = 0; i < ui->CountOfCodes; i++) { const bfd_byte *t; t = insns[insns_count++] = &dta[i * 2]; switch (PEX64_UNWCODE_CODE (t[1])) { 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; } } 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;) { --i; dta = insns[i]; fprintf (file, "\t insn ends at 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])]); break; case UWOP_ALLOC_LARGE: if (PEX64_UNWCODE_INFO (dta[1]) == 0) { tmp = (bfd_vma) (*((unsigned short *) &dta[2])); tmp *= 8; } else tmp = (bfd_vma) (*((unsigned int *)&dta[2])); fprintf (file, "save stack region of size 0x"); fprintf_vma (file, tmp); fprintf (file,".\n"); 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"); 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"); 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"); 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"); 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"); 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"); 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"); 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"); 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)"); } else fprintf (file, ", unknown(%u))", (unsigned int) PEX64_UNWCODE_INFO (dta[1])); fprintf (file,".\n"); break; default: fprintf (file, "unknown code %u.\n", (unsigned int) PEX64_UNWCODE_INFO (dta[1])); break; } } }
void vfinfo (FILE *fp, const char *fmt, va_list ap, bfd_boolean is_warning) { bfd_boolean fatal = FALSE; const char *scan; int arg_type; unsigned int arg_count = 0; unsigned int arg_no; union vfinfo_args { int i; long l; void *p; bfd_vma v; struct { bfd *abfd; asection *sec; bfd_vma off; } reladdr; enum { Bad, Int, Long, Ptr, Vma, RelAddr } type; } args[9]; for (arg_no = 0; arg_no < sizeof (args) / sizeof (args[0]); arg_no++) args[arg_no].type = Bad; arg_count = 0; scan = fmt; while (*scan != '\0') { while (*scan != '%' && *scan != '\0') scan++; if (*scan == '%') { scan++; arg_no = arg_count; if (*scan != '0' && ISDIGIT (*scan) && scan[1] == '$') { arg_no = *scan - '1'; scan += 2; } arg_type = Bad; switch (*scan++) { case '\0': --scan; break; case 'V': case 'v': case 'W': arg_type = Vma; break; case 's': arg_type = Ptr; break; case 'p': if (*scan == 'A' || *scan == 'B' || *scan == 'I' || *scan == 'R' || *scan == 'S' || *scan == 'T') scan++; arg_type = Ptr; break; case 'C': case 'D': case 'G': case 'H': arg_type = RelAddr; break; case 'd': case 'u': arg_type = Int; break; case 'l': if (*scan == 'd' || *scan == 'u') { ++scan; arg_type = Long; } break; default: break; } if (arg_type != Bad) { if (arg_no >= sizeof (args) / sizeof (args[0])) abort (); args[arg_no].type = arg_type; ++arg_count; } } } for (arg_no = 0; arg_no < arg_count; arg_no++) { switch (args[arg_no].type) { case Int: args[arg_no].i = va_arg (ap, int); break; case Long: args[arg_no].l = va_arg (ap, long); break; case Ptr: args[arg_no].p = va_arg (ap, void *); break; case Vma: args[arg_no].v = va_arg (ap, bfd_vma); break; case RelAddr: args[arg_no].reladdr.abfd = va_arg (ap, bfd *); args[arg_no].reladdr.sec = va_arg (ap, asection *); args[arg_no].reladdr.off = va_arg (ap, bfd_vma); break; default: abort (); } } arg_count = 0; while (*fmt != '\0') { const char *str = fmt; while (*fmt != '%' && *fmt != '\0') fmt++; if (fmt != str) if (fwrite (str, 1, fmt - str, fp)) { /* Ignore. */ } if (*fmt == '%') { fmt++; arg_no = arg_count; if (*fmt != '0' && ISDIGIT (*fmt) && fmt[1] == '$') { arg_no = *fmt - '1'; fmt += 2; } switch (*fmt++) { case '\0': --fmt; /* Fall through. */ case '%': /* literal % */ putc ('%', fp); break; case 'X': /* no object output, fail return */ config.make_executable = FALSE; break; case 'V': /* hex bfd_vma */ { bfd_vma value = args[arg_no].v; ++arg_count; fprintf_vma (fp, value); } break; case 'v': /* hex bfd_vma, no leading zeros */ { char buf[100]; char *p = buf; bfd_vma value = args[arg_no].v; ++arg_count; sprintf_vma (p, value); while (*p == '0') p++; if (!*p) p--; fputs (p, fp); } break; case 'W': /* hex bfd_vma with 0x with no leading zeroes taking up 8 spaces. */ { char buf[100]; bfd_vma value; char *p; int len; value = args[arg_no].v; ++arg_count; sprintf_vma (buf, value); for (p = buf; *p == '0'; ++p) ; if (*p == '\0') --p; len = strlen (p); while (len < 8) { putc (' ', fp); ++len; } fprintf (fp, "0x%s", p); } break; case 'F': /* Error is fatal. */ fatal = TRUE; break; case 'P': /* Print program name. */ fprintf (fp, "%s", program_name); break; case 'E': /* current bfd error or errno */ fprintf (fp, "%s", bfd_errmsg (bfd_get_error ())); break; case 'C': case 'D': case 'G': case 'H': /* Clever filename:linenumber with function name if possible. The arguments are a BFD, a section, and an offset. */ { static bfd *last_bfd; static char *last_file; static char *last_function; bfd *abfd; asection *section; bfd_vma offset; asymbol **asymbols = NULL; const char *filename; const char *functionname; unsigned int linenumber; bfd_boolean discard_last; bfd_boolean done; abfd = args[arg_no].reladdr.abfd; section = args[arg_no].reladdr.sec; offset = args[arg_no].reladdr.off; ++arg_count; if (abfd != NULL) { if (!bfd_generic_link_read_symbols (abfd)) einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd); asymbols = bfd_get_outsymbols (abfd); } /* The GNU Coding Standard requires that error messages be of the form: source-file-name:lineno: message We do not always have a line number available so if we cannot find them we print out the section name and offset instead. */ discard_last = TRUE; if (abfd != NULL && bfd_find_nearest_line (abfd, section, asymbols, offset, &filename, &functionname, &linenumber)) { if (functionname != NULL && (fmt[-1] == 'C' || fmt[-1] == 'H')) { /* Detect the case where we are printing out a message for the same function as the last call to vinfo ("%C"). In this situation do not print out the ABFD filename or the function name again. Note - we do still print out the source filename, as this will allow programs that parse the linker's output (eg emacs) to correctly locate multiple errors in the same source file. */ if (last_bfd == NULL || last_function == NULL || last_bfd != abfd || (last_file == NULL) != (filename == NULL) || (filename != NULL && filename_cmp (last_file, filename) != 0) || strcmp (last_function, functionname) != 0) { lfinfo (fp, _("%pB: in function `%pT':\n"), abfd, functionname); last_bfd = abfd; if (last_file != NULL) free (last_file); last_file = NULL; if (filename) last_file = xstrdup (filename); if (last_function != NULL) free (last_function); last_function = xstrdup (functionname); } discard_last = FALSE; } else lfinfo (fp, "%pB:", abfd); if (filename != NULL) fprintf (fp, "%s:", filename); done = fmt[-1] != 'H'; if (functionname != NULL && fmt[-1] == 'G') lfinfo (fp, "%pT", functionname); else if (filename != NULL && linenumber != 0) fprintf (fp, "%u%s", linenumber, done ? "" : ":"); else done = FALSE; } else { lfinfo (fp, "%pB:", abfd); done = FALSE; } if (!done) lfinfo (fp, "(%pA+0x%v)", section, offset); if (discard_last) { last_bfd = NULL; if (last_file != NULL) { free (last_file); last_file = NULL; } if (last_function != NULL) { free (last_function); last_function = NULL; } } } break; case 'p': if (*fmt == 'A') { /* section name from a section */ asection *sec; bfd *abfd; const char *group = NULL; struct coff_comdat_info *ci; fmt++; sec = (asection *) args[arg_no].p; ++arg_count; abfd = sec->owner; fprintf (fp, "%s", sec->name); if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_elf_flavour && elf_next_in_group (sec) != NULL && (sec->flags & SEC_GROUP) == 0) group = elf_group_name (sec); else if (abfd != NULL && bfd_get_flavour (abfd) == bfd_target_coff_flavour && (ci = bfd_coff_get_comdat_section (sec->owner, sec)) != NULL) group = ci->name; if (group != NULL) fprintf (fp, "[%s]", group); } else if (*fmt == 'B') { /* filename from a bfd */ bfd *abfd = (bfd *) args[arg_no].p; fmt++; ++arg_count; if (abfd == NULL) fprintf (fp, "%s generated", program_name); else if (abfd->my_archive != NULL && !bfd_is_thin_archive (abfd->my_archive)) fprintf (fp, "%s(%s)", abfd->my_archive->filename, abfd->filename); else fprintf (fp, "%s", abfd->filename); } else if (*fmt == 'I') { /* filename from a lang_input_statement_type */ lang_input_statement_type *i; fmt++; i = (lang_input_statement_type *) args[arg_no].p; ++arg_count; if (i->the_bfd != NULL && i->the_bfd->my_archive != NULL && !bfd_is_thin_archive (i->the_bfd->my_archive)) fprintf (fp, "(%s)%s", i->the_bfd->my_archive->filename, i->local_sym_name); else fprintf (fp, "%s", i->filename); } else if (*fmt == 'R') { /* Print all that's interesting about a relent. */ arelent *relent = (arelent *) args[arg_no].p; fmt++; ++arg_count; lfinfo (fp, "%s+0x%v (type %s)", (*(relent->sym_ptr_ptr))->name, relent->addend, relent->howto->name); } else if (*fmt == 'S') { /* Print script file and linenumber. */ etree_type node; etree_type *tp = (etree_type *) args[arg_no].p; fmt++; ++arg_count; if (tp == NULL) { tp = &node; tp->type.filename = ldlex_filename (); tp->type.lineno = lineno; } if (tp->type.filename != NULL) fprintf (fp, "%s:%u", tp->type.filename, tp->type.lineno); } else if (*fmt == 'T') { /* Symbol name. */ const char *name = (const char *) args[arg_no].p; fmt++; ++arg_count; if (name == NULL || *name == 0) { fprintf (fp, _("no symbol")); break; } else if (demangling) { char *demangled; demangled = bfd_demangle (link_info.output_bfd, name, DMGL_ANSI | DMGL_PARAMS); if (demangled != NULL) { fprintf (fp, "%s", demangled); free (demangled); break; } } fprintf (fp, "%s", name); } else { /* native (host) void* pointer, like printf */ fprintf (fp, "%p", args[arg_no].p); ++arg_count; } break; case 's': /* arbitrary string, like printf */ fprintf (fp, "%s", (char *) args[arg_no].p); ++arg_count; break; case 'd': /* integer, like printf */ fprintf (fp, "%d", args[arg_no].i); ++arg_count; break; case 'u': /* unsigned integer, like printf */ fprintf (fp, "%u", args[arg_no].i); ++arg_count; break; case 'l': if (*fmt == 'd') { fprintf (fp, "%ld", args[arg_no].l); ++arg_count; ++fmt; break; } else if (*fmt == 'u') { fprintf (fp, "%lu", args[arg_no].l); ++arg_count; ++fmt; break; } /* Fallthru */ default: fprintf (fp, "%%%c", fmt[-1]); break; } } } if (is_warning && config.fatal_warnings) config.make_executable = FALSE; if (fatal) xexit (1); }
static bfd_boolean pex64_bfd_print_pdata (bfd *abfd, void *vfile) { FILE *file = (FILE *) vfile; 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 = NULL; int xdata_arr_cnt; /* 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, pdata_section)->virt_size; /* PR 17512: file: 005-181405-0.004. */ if (stop == 0 || pdata_section->size == 0) { fprintf (file, _("No unwind data in .pdata section\n")); return TRUE; } 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")); 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; 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, &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 + pdata_section->vma); fprintf (file, ":\t"); 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) { seen_error = 1; fprintf (file, " has %s begin address as predecessor\n", (rf.rva_BeginAddress < prev_beginaddress ? "smaller" : "same")); } prev_beginaddress = rf.rva_BeginAddress; /* Now we check for negative addresses. */ if ((prev_beginaddress & 0x80000000) != 0) { seen_error = 1; fprintf (file, " has negative begin address\n"); } if ((rf.rva_EndAddress & 0x80000000) != 0) { seen_error = 1; fprintf (file, " has negative end address\n"); } if ((rf.rva_UnwindData & 0x80000000) != 0) { seen_error = 1; fprintf (file, " has negative unwind address\n"); } if (rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf)) xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData; } if (seen_error) goto done; /* Add end of list marker. */ xdata_arr[xdata_arr_cnt++] = ~((bfd_vma) 0); /* Sort start RVAs of xdata. */ if (xdata_arr_cnt > 1) qsort (xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma), sort_xdata_arr); /* 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, &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; if (i == 0) fprintf (file, "\nDump of .xdata\n"); fputc (' ', file); 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; 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 (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf)) { 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 { bfd_vma *p; /* Search for the current entry in the sorted array. */ p = (bfd_vma *) bsearch (&rf.rva_UnwindData, xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma), sort_xdata_arr); /* Advance to the next pointer into the xdata section. We may have shared xdata entries, which will result in a string of identical pointers in the array; advance past all of them. */ while (p[0] <= rf.rva_UnwindData) ++p; if (p[0] == ~((bfd_vma) 0)) p = NULL; pex64_dump_xdata (file, abfd, xdata_section, xdata, p, &rf); } } } done: free (pdata); free (xdata_arr); free (xdata); return TRUE; }