diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 984ab433bf..a12f7b980a 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +2009-04-21 Kai Tietz + + * coff-x86_64.c (PEI_HEADERS): Protect includes. + (bfd_pe_print_pdata): Remove #ifdef PE variation. + * pei-x86_64.c (PEI_HEADERS): Define to prevent double + include in coff-x86_64.c of headers. + (PDATA_ROW_SIZE): New define. + (pex_regs[]): New static array. + (pex64_get_runtime_function): New static function. + (pex64_get_unwind_info): Likewise. + (pex64_get_scope_entry): Likewise. + (pex64_xdata_print_uwd_codes): Likewise. + (pex64_get_section_by_rva): Likewise. + (pex64_dump_xdata): Likewise. + (pex64_bfd_print_pdata): Likewise. + (bfd_pe_print_pdata): Define as pex64_bfd_print_pdata. + * peXXigen.c (_bfd_pex64_print_pdata): Removed implementation. + * libpei.h (_bfd_pex64_print_pdata): Removed declaration. + 2009-04-19 Peter O'Gorman Alan Modra Dave Korn diff --git a/bfd/coff-x86_64.c b/bfd/coff-x86_64.c index ec78fbfafd..3d7ff609c5 100644 --- a/bfd/coff-x86_64.c +++ b/bfd/coff-x86_64.c @@ -24,6 +24,10 @@ #define COFF_WITH_pex64 #endif +/* Note we have to make sure not to include headers twice. + Not all headers are wrapped in #ifdef guards, so we define + PEI_HEADERS to prevent double including here. */ +#ifndef PEI_HEADERS #include "sysdep.h" #include "bfd.h" #include "libbfd.h" @@ -32,6 +36,7 @@ #include "coff/pe.h" #include "libcoff.h" #include "libiberty.h" +#endif #define BADMAG(x) AMD64BADMAG(x) @@ -711,14 +716,9 @@ coff_amd64_is_local_label_name (bfd *abfd, const char *name) #endif /* TARGET_UNDERSCORE */ -#ifdef PE -#undef bfd_pe_print_pdata -#define bfd_pe_print_pdata _bfd_pex64_print_pdata -#else /* PE */ #ifndef bfd_pe_print_pdata #define bfd_pe_print_pdata NULL #endif -#endif /* PE */ #include "coffcode.h" diff --git a/bfd/libpei.h b/bfd/libpei.h index f5bfa4cac3..ac40f3b703 100644 --- a/bfd/libpei.h +++ b/bfd/libpei.h @@ -354,4 +354,3 @@ bfd_boolean _bfd_pe64_print_ce_compressed_pdata (bfd *, void *); bfd_boolean _bfd_pex64_print_ce_compressed_pdata (bfd *, void *); bfd_boolean _bfd_pep_print_ce_compressed_pdata (bfd *, void *); -bfd_boolean _bfd_pex64_print_pdata (bfd *, void *); diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index fe712a6f0e..69657fcf62 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -1903,87 +1903,6 @@ _bfd_XX_print_ce_compressed_pdata (bfd * abfd, void * vfile) #undef PDATA_ROW_SIZE } -#ifdef COFF_WITH_pex64 -/* The PE+ x64 variant. */ -bfd_boolean -_bfd_pex64_print_pdata (bfd *abfd, void *vfile) -{ -# define PDATA_ROW_SIZE (3 * 4) - 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; - struct sym_cache sym_cache = {0, 0}; - - 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) - { - bfd_vma begin_addr; - bfd_vma end_addr; - bfd_vma unwind_data_addr; - - if (i + PDATA_ROW_SIZE > stop) - break; - - begin_addr = bfd_get_32 (abfd, data + i); - end_addr = bfd_get_32 (abfd, data + i + 4); - unwind_data_addr = bfd_get_32 (abfd, data + i + 8); - - if (begin_addr == 0 && end_addr == 0 && unwind_data_addr == 0) - /* We are probably into the padding of the section now. */ - break; - - fputc (' ', file); - fprintf_vma (file, i + section->vma); - fprintf (file, ":\t"); - fprintf_vma (file, begin_addr); - fputc (' ', file); - fprintf_vma (file, end_addr); - fputc (' ', file); - fprintf_vma (file, unwind_data_addr); - - fprintf (file, "\n"); - } - - free (data); - - cleanup_syms (&sym_cache); - - return TRUE; -#undef PDATA_ROW_SIZE -} -#endif #define IMAGE_REL_BASED_HIGHADJ 4 static const char * const tbl[] = diff --git a/bfd/pei-x86_64.c b/bfd/pei-x86_64.c index f62e69765a..f5b8abdc8a 100644 --- a/bfd/pei-x86_64.c +++ b/bfd/pei-x86_64.c @@ -34,6 +34,7 @@ #define COFF_LONG_SECTION_NAMES 0 #define COFF_SUPPORT_GNU_LINKONCE #define COFF_LONG_FILENAMES +#define PDATA_ROW_SIZE (3 * 4) #define COFF_SECTION_ALIGNMENT_ENTRIES \ { COFF_SECTION_NAME_EXACT_MATCH (".bss"), \ @@ -53,4 +54,478 @@ { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi."), \ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 } +/* Note we have to make sure not to include headers twice. + Not all headers are wrapped in #ifdef guards, so we define + PEI_HEADERS to prevent double including in coff-x86_64.c */ +#define PEI_HEADERS +#include "sysdep.h" +#include "bfd.h" +#include "libbfd.h" +#include "coff/x86_64.h" +#include "coff/internal.h" +#include "coff/pe.h" +#include "libcoff.h" +#include "libpei.h" +#include "libiberty.h" + +#undef AOUTSZ +#define AOUTSZ PEPAOUTSZ +#define PEAOUTHDR PEPAOUTHDR + +static const char *pex_regs[16] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; + +static void +pex64_get_runtime_function (bfd *abfd, struct pex64_runtime_function *rf, + const void *data) +{ + const struct external_pex64_runtime_function *ex_rf = + (const struct external_pex64_runtime_function *) data; + 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); +} + +static void +pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data) +{ + struct external_pex64_unwind_info *ex_ui = + (struct external_pex64_unwind_info *) data; + bfd_byte *ex_dta = (bfd_byte *) data; + + memset (ui, 0, sizeof (struct pex64_unwind_info)); + ui->Version = PEX64_UWI_VERSION (ex_ui->Version_Flags); + ui->Flags = PEX64_UWI_FLAGS (ex_ui->Version_Flags); + ui->SizeOfPrologue = (bfd_vma) ex_ui->SizeOfPrologue; + ui->CountOfCodes = (bfd_vma) ex_ui->CountOfCodes; + ui->FrameRegister = PEX64_UWI_FRAMEREG (ex_ui->FrameRegisterOffset); + ui->FrameOffset = PEX64_UWI_FRAMEOFF (ex_ui->FrameRegisterOffset); + ui->sizeofUnwindCodes = PEX64_UWI_SIZEOF_UWCODE_ARRAY (ui->CountOfCodes); + ui->SizeOfBlock = ui->sizeofUnwindCodes + 4; + ui->rawUnwindCodes = &ex_dta[4]; + ex_dta += ui->SizeOfBlock; + switch (ui->Flags) + { + case UNW_FLAG_EHANDLER: + ui->rva_ExceptionHandler = bfd_get_32 (abfd, ex_dta); + break; + case UNW_FLAG_UHANDLER: + ui->rva_TerminationHandler = bfd_get_32 (abfd, ex_dta); + break; + case UNW_FLAG_FHANDLER: + ui->rva_FrameHandler = bfd_get_32 (abfd, ex_dta); + ui->FrameHandlerArgument = bfd_get_32 (abfd, ex_dta + 4); + ui->SizeOfBlock += 8; + return; + case UNW_FLAG_CHAININFO: + ui->rva_FunctionEntry = bfd_get_32 (abfd, ex_dta); + ui->SizeOfBlock += 4; + return; + default: + return; + } + ex_dta += 4; + ui->SizeOfBlock += 8; + ui->CountOfScopes = bfd_get_32 (abfd, ex_dta); + ex_dta += 4; + ui->rawScopeEntries = ex_dta; + ui->SizeOfBlock += (ui->CountOfScopes * PEX64_SCOPE_ENTRY_SIZE); +} + +static void +pex64_get_scope_entry (bfd *abfd, struct pex64_scope_entry *se, + bfd_vma idx, const bfd_byte *x) +{ + const struct external_pex64_scope_entry *ex_se; + x += (idx * PEX64_SCOPE_ENTRY_SIZE); + ex_se = (const struct external_pex64_scope_entry *) x; + memset (se, 0, sizeof (struct pex64_scope_entry)); + se->rva_BeginAddress = bfd_get_32 (abfd, ex_se->rva_BeginAddress); + se->rva_EndAddress = bfd_get_32 (abfd, ex_se->rva_EndAddress); + se->rva_HandlerAddress = bfd_get_32 (abfd, ex_se->rva_HandlerAddress); + se->rva_JumpAddress = bfd_get_32 (abfd, ex_se->rva_JumpAddress); +} + +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; + } + } +} + +static asection * +pex64_get_section_by_rva (bfd *abfd, bfd_vma addr, const char *sec_name) +{ + asection *section = bfd_get_section_by_name (abfd, sec_name); + bfd_vma vsize; + bfd_size_type datasize = 0; + + if (section == NULL + || coff_section_data (abfd, section) == NULL + || pei_section_data (abfd, section) == NULL) + return NULL; + vsize = section->vma - pe_data (abfd)->pe_opthdr.ImageBase; + datasize = section->size; + if (!datasize || vsize > addr || (vsize + datasize) < addr) + return NULL; + return section; +} + +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 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; +} + +#define bfd_pe_print_pdata pex64_bfd_print_pdata + #include "coff-x86_64.c" diff --git a/include/ChangeLog b/include/ChangeLog index dfe9fcee96..c94f74cf8a 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,32 @@ +2009-04-21 Kai Tietz + + * coff/pe.h (pex64_runtime_function): New structure. + (external_pex64_runtime_function): Likewise. + (pex64_unwind_code): Likewise. + (external_pex64_unwind_code): Likewise. + (pex64_unwind_info): Likewise. + (external_pex64_unwind_info): Likewise. + (external_pex64_scope): Likewise. + (pex64_scope): Likewise. + (pex64_scope_entry): Likewise. + (external_pex64_scope_entry): Likewise. + (PEX64_IS_RUNTIME_FUNCTION_CHAINED): New macro. + (PEX64_GET_UNWINDDATA_UNIFIED_RVA): Likewise. + (PEX64_UNWCODE_CODE): Likewise. + (PEX64_UNWCODE_INFO): Likewise. + (UWOP_...): Add defines for unwind code. + (UNW_FLAG_...): Add defined for unwind info flags. + (PEX64_SCOPE_ENTRY_SIZE): New macro. + (PEX64_UWI_VERSION): Likewise. + (PEX64_UWI_FLAGS): Likewise. + (PEX64_UWI_FRAMEREG): Likewise. + (PEX64_UWI_FRAMEOFF): Likewise. + (PEX64_UWI_SIZEOF_UWCODE_ARRAY): Likewise. + (PEX64_OFFSET_TO_UNWIND_CODE): Likewise. + (PEX64_OFFSET_TO_HANDLER_RVA): Likewise. + (PEX64_OFFSET_TO_SCOPE_COUNT): Likewise. + (PEX64_SCOPE_ENTRY): Likewise. + 2009-04-08 H.J. Lu * bfdlink.h (bfd_link_info): Add warn_alternate_em. diff --git a/include/coff/pe.h b/include/coff/pe.h index c7e7bd26f6..e8bf681ba3 100644 --- a/include/coff/pe.h +++ b/include/coff/pe.h @@ -358,4 +358,154 @@ typedef struct #define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 #define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 +/* .pdata/.xdata defines and structures for x64 PE+ for exception handling. */ + +/* .pdata in exception directory. */ + +struct pex64_runtime_function +{ + bfd_vma rva_BeginAddress; + bfd_vma rva_EndAddress; + bfd_vma rva_UnwindData; + unsigned int isChained : 1; +}; + +struct external_pex64_runtime_function +{ + bfd_byte rva_BeginAddress[4]; + bfd_byte rva_EndAddress[4]; + bfd_byte rva_UnwindData[4]; +}; + +/* If the lowest significant bit is set for rva_UnwindData RVA, it + means that the unified RVA points to another pex64_runtime_function + that this entry shares the unwind_info block with. */ +#define PEX64_IS_RUNTIME_FUNCTION_CHAINED(PTR_RTF) \ + (((PTR_RTF)->rva_UnwindData & 1) != 0) +#define PEX64_GET_UNWINDDATA_UNIFIED_RVA(PTR_RTF) \ + ((PTR_RTF)->rva_UnwindData & ~1) + +/* The unwind codes. */ +#define UWOP_PUSH_NONVOL 0 +#define UWOP_ALLOC_LARGE 1 +#define UWOP_ALLOC_SMALL 2 +#define UWOP_SET_FPREG 3 +#define UWOP_SAVE_NONVOL 4 +#define UWOP_SAVE_NONVOL_FAR 5 +#define UWOP_SAVE_XMM 6 +#define UWOP_SAVE_XMM_FAR 7 +#define UWOP_SAVE_XMM128 8 +#define UWOP_SAVE_XMM128_FAR 9 +#define UWOP_PUSH_MACHFRAME 10 + +struct pex64_unwind_code +{ + bfd_vma prologue_offset; + /* Contains Frame offset, or frame allocation size. */ + bfd_vma frame_addr; + unsigned int uwop_code : 4; + /* xmm, mm, or standard register from 0 - 15. */ + unsigned int reg : 4; + /* Used for UWOP_PUSH_MACHFRAME to indicate optional errorcode stack + argument. */ + unsigned int has_errorcode : 1; +}; + +struct external_pex64_unwind_code +{ + bfd_byte dta[2]; +}; + +#define PEX64_UNWCODE_CODE(VAL) ((VAL) & 0xf) +#define PEX64_UNWCODE_INFO(VAL) (((VAL) >> 4) & 0xf) + +/* The unwind info. */ +#define UNW_FLAG_NHANDLER 0 +#define UNW_FLAG_EHANDLER 1 +#define UNW_FLAG_UHANDLER 2 +#define UNW_FLAG_FHANDLER 3 +#define UNW_FLAG_CHAININFO 4 + +#define UNW_FLAG_MASK 0x1f + +struct pex64_unwind_info +{ + bfd_vma SizeOfBlock; + bfd_byte Version; /* Values from 0 up to 7 are possible. */ + bfd_byte Flags; /* Values from 0 up to 31 are possible. */ + bfd_vma SizeOfPrologue; + bfd_vma CountOfCodes; /* Amount of pex64_unwind_code elements. */ + /* 0 = CFA, 1..15 are index of integer registers. */ + unsigned int FrameRegister : 4; + bfd_vma FrameOffset; + bfd_vma sizeofUnwindCodes; + bfd_byte *rawUnwindCodes; + /* Valid for UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER. */ + bfd_vma CountOfScopes; + bfd_byte *rawScopeEntries; + bfd_vma rva_ExceptionHandler; /* UNW_EHANDLER. */ + bfd_vma rva_TerminationHandler; /* UNW_FLAG_UHANDLER. */ + bfd_vma rva_FrameHandler; /* UNW_FLAG_FHANDLER. */ + bfd_vma FrameHandlerArgument; /* UNW_FLAG_FHANDLER. */ + bfd_vma rva_FunctionEntry; /* UNW_FLAG_CHAININFO. */ +}; + +struct external_pex64_unwind_info +{ + bfd_byte Version_Flags; + bfd_byte SizeOfPrologue; + bfd_byte CountOfCodes; + bfd_byte FrameRegisterOffset; + /* external_pex64_unwind_code array. */ + /* bfd_byte handler[4]; */ + /* Optional language specific data. */ +}; + +struct external_pex64_scope +{ + bfd_vma Count; +}; + +struct pex64_scope +{ + bfd_byte Count[4]; +}; + +struct pex64_scope_entry +{ + bfd_vma rva_BeginAddress; + bfd_vma rva_EndAddress; + bfd_vma rva_HandlerAddress; + bfd_vma rva_JumpAddress; +}; +#define PEX64_SCOPE_ENTRY_SIZE 16 + +struct external_pex64_scope_entry +{ + bfd_byte rva_BeginAddress[4]; + bfd_byte rva_EndAddress[4]; + bfd_byte rva_HandlerAddress[4]; + bfd_byte rva_JumpAddress[4]; +}; + +#define PEX64_UWI_VERSION(VAL) ((VAL) & 7) +#define PEX64_UWI_FLAGS(VAL) (((VAL) >> 3) & 0x1f) +#define PEX64_UWI_FRAMEREG(VAL) ((VAL) & 0xf) +#define PEX64_UWI_FRAMEOFF(VAL) (((VAL) >> 4) & 0xf) +#define PEX64_UWI_SIZEOF_UWCODE_ARRAY(VAL) \ + ((((VAL) + 1) & ~1) * 2) + +#define PEX64_OFFSET_TO_UNWIND_CODE 0x4 + +#define PEX64_OFFSET_TO_HANDLER_RVA (COUNTOFUNWINDCODES) \ + (PEX64_OFFSET_TO_UNWIND_CODE + \ + PEX64_UWI_SIZEOF_UWCODE_ARRAY(COUNTOFUNWINDCODES)) + +#define PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) \ + (PEX64_OFFSET_TO_HANDLER_RVA(COUNTOFUNWINDCODES) + 4) + +#define PEX64_SCOPE_ENTRY(COUNTOFUNWINDCODES, IDX) \ + (PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \ + PEX64_SCOPE_ENTRY_SIZE * (IDX)) + #endif /* _PE_H */