diff options
Diffstat (limited to 'backends')
102 files changed, 12228 insertions, 0 deletions
diff --git a/backends/ChangeLog b/backends/ChangeLog new file mode 100644 index 00000000..e800d16b --- /dev/null +++ b/backends/ChangeLog @@ -0,0 +1,790 @@ +2014-12-18 Ulrich Drepper <drepper@gmail.com> + + * Makefile.am: Suppress output of textrel_check command. + +2014-11-22 Mark Wielaard <mjw@redhat.com> + + * ppc64_symbol.c (ppc64_bss_plt_p): Remove ehdr argument. + * ppc_symbol.c (find_dyn_got): Likewise. Use elf_getphdrnum. + (ppc_check_special_symbol): Call find_dyn_got without ehdr. + (ppc_bss_plt_p): Remove ehdr argument. + +2014-11-17 Mark Wielaard <mjw@redhat.com> + + * ppc64_init.c (ppc64_init): Check section name is not NULL. + +2014-10-06 Mark Wielaard <mjw@redhat.com> + + * libebl_CPU.h (dwarf_peel_type): Removed. + (dwarf_peeled_die_type): Use libdw dwarf_peel_type. + +2014-07-18 Kyle McMartin <kyle@redhat.com> + Mark Wielaard <mjw@redhat.com> + + * aarch64_initreg.c: Check HAVE_SYS_USER_REGS. + (aarch64_set_initial_registers_tid): Use user_regs_struct and + user_fpsimd_struct. + * arm_initreg.c: Check HAVE_SYS_USER_REGS. + (arm_set_initial_registers_tid): Use user_regs_struct in compat mode. + +2014-07-04 Menanteau Guy <menantea@linux.vnet.ibm.com> + Mark Wielaard <mjw@redhat.com> + + * ppc64_init.c (ppc64_init): Hook check_st_other_bits. + * ppc64_reloc.def: TLSGD, TLSLD, TOCSAVE, ADDR16_HIGH, ADDR16_HIGHA, + TPREL16_HIGH, TPREL16_HIGHA, DTPREL16_HIGH, DTPREL16_HIGHA, JMP_IREL, + IRELATIVE, REL16, REL16_LO, REL16_HI and REL16_HA. + * ppc64_symbol.c (ppc64_dynamic_tag_name): Recognize DT_PPC64_OPT. + (ppc64_dynamic_tag_check): Likewise. + (ppc64_check_st_other_bits): New function. + +2014-07-04 Mark Wielaard <mjw@redhat.com> + + * aarch64_retval.c (aarch64_return_value_location): Handle + DW_ATE_boolean. + +2014-06-18 Mark Wielaard <mjw@redhat.com> + + * libebl_CPU.h (dwarf_peel_type): Remove DW_TAG_mutable_type + handling. + +2014-06-17 Mark Wielaard <mjw@redhat.com> + + * arm_init.c (arm_init): Set func_addr_mask. + +2014-06-20 Petr Machata <pmachata@redhat.com> + + * alpha_retval.c (alpha_return_value_location): Call + dwarf_peeled_die_type instead of inlining equivalent code. + * arm_retval.c (arm_return_value_location): Likewise. + * i386_retval.c (i386_return_value_location): Likewise. + * ia64_retval.c (ia64_return_value_location): Likewise. + * ppc64_retval.c (ppc64_return_value_location): Likewise. + * ppc_retval.c (ppc_return_value_location): Likewise. + * s390_retval.c (s390_return_value_location): Likewise. + * sh_retval.c (sh_return_value_location): Likewise. + * sparc_retval.c (sparc_return_value_location): Likewise. + * tilegx_retval.c (tilegx_return_value_location): Likewise. + * x86_64_retval.c (x86_64_return_value_location): Likewise. + +2014-05-19 Mark Wielaard <mjw@redhat.com> + + * arm_init.c (arm_init): Hook check_reloc_target_type. + * arm_symbol.c (arm_check_reloc_target_type): New function. + * ia64_init.c (ia64_init): Hook check_reloc_target_type. + * ia64_symbol.c (ia64_check_reloc_target_type): New function. + +2014-04-22 Kurt Roeckx <kurt@roeckx.be> + + * i386_initreg.c: Make Linux only. + * x86_64_initreg.c: Make Linux only. + +2014-04-13 Mark Wielaard <mjw@redhat.com> + + * Makefile.am: Remove libelf and libdw definitions when MUDFLAP + is defined. Remove libmudflap from LINK line. + +2014-04-09 Mark Wielaard <mjw@redhat.com> + + * Makefile.am (aarch64_SRCS): Add aarch64_initreg.c. + * aarch64_corenote.c (prstatus_regs): Mark pc_register. + * aarch64_init.c: Assign frame_nregs. Hook set_initial_registers_tid. + * aarch64_initreg: New file. + +2014-03-28 Jean Pihet <jean.pihet@linaro.org> + + * arm_initreg.c (arm_set_initial_registers_tid): Handle compat mode. + ARM compatible code running on AARCH64. + +2014-03-19 Mark Wielaard <mjw@redhat.com> + + * aarch64_reloc.def: AARCH64_ABS32 and AARCH64_ABS64 are also valid + in ET_REL. + +2014-01-30 Petr Machata <pmachata@redhat.com> + + * aarch64_regs.c (aarch64_register_info.regtype): Make this + variadic printf-like function. Call one vsnprintf instead of two + snprintf's. + (regtyper, regtypen): Drop. + (aarch64_register_info): Adjust callers. + +2014-01-26 Mark Wielaard <mjw@redhat.com> + + * Makefile.am (arm_SRCS): Add arm_initreg.c. + * arm_init.c (arm_init): Define frame_nregs and hook + set_initial_registers_tid. + * arm_initreg.c: New file. + +2014-01-25 Mark Wielaard <mjw@redhat.com> + + * arm_cfi.c (arm_abi_cfi): Restore SP (r13) from CFA. + +2014-01-24 Mark Wielaard <mjw@redhat.com> + + * arm_reloc.def: Update list. + +2014-01-22 Mark Wielaard <mjw@redhat.com> + + * Makefile.am (aarch64_regs_no_Wformat): Removed. + * aarch64_regs.c (regtype): Add bool nr argument. snprintf arg + when nr is true. + (regtyper): New function. + (regtypen): Likewise. + (aarch64_register_info): Call either regtyper or regtypen not + regtype directly. + +2014-01-14 Mark Wielaard <mjw@redhat.com> + + * aarch64_symbol.c (aarch64_check_special_symbol): Check shdr is + not NULL before usage. + +2014-01-04 Mark Wielaard <mjw@redhat.com> + + * ppc64_symbol.c (ppc64_machine_flag_check): New function. + * ppc64_init.c (ppc64_init): Hook machine_flag_check. + +2014-01-03 Mark Wielaard <mjw@redhat.com> + + * Makefile.am (aarch64_SRCS): Add aarch64_cfi.c. + * aarch64_cfi.c: New file. + * aarch64_init.c (aarch64_init): Hook abi_cfi. + * aarch64_regs.c (aarch64_register_info): Set *prefix to "". + +2013-12-19 Mark Wielaard <mjw@redhat.com> + + * aarch64_init.c (aarch64_init): Hook check_special_symbol. + * aarch64_symbol.c (aarch64_check_special_symbol): New function. + +2013-12-18 Mark Wielaard <mjw@redhat.com> + + * Makefile.am (ppc64_SRCS): Add ppc64_resolve_sym.c. + * ppc64_resolve_sym.c: New file. + * ppc64_init.c: Hook resolve_sym_value and find function descriptor + table. + +2013-12-18 Mark Wielaard <mjw@redhat.com> + + * s390_initreg.c (s390_set_initial_registers_tid): Use union + to avoid type-punning when assigning a double to a Dwarf_Word. + +2013-12-18 Jan Kratochvil <jan.kratochvil@redhat.com> + + unwinder: s390 and s390x + * Makefile.am (s390_SRCS): Add s390_initreg.c and s390_unwind.c. + * s390_corenote.c (prstatus_regs): Set PC_REGISTER. Reindent all the + entries. + * s390_init.c (s390_init): Initialize frame_nregs, + set_initial_registers_tid, normalize_pc and unwind. + * s390_initreg.c: New file. + * s390_unwind.c: New file. + +2013-12-15 Jan Kratochvil <jan.kratochvil@redhat.com> + + unwinder: ppc and ppc64 + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add ppc_initreg.c. + * ppc64_init.c (ppc64_init): Initialize also frame_nregs, + set_initial_registers_tid and dwarf_to_regno. + * ppc_corenote.c (PRSTATUS_REGSET_ITEMS) <nip>: Set PC_REGISTER. + * ppc_init.c (ppc64_init): Initialize also frame_nregs, + set_initial_registers_tid and dwarf_to_regno. + * ppc_initreg.c: New file. + +2013-11-25 Petr Machata <pmachata@redhat.com> + + * Makefile.am (modules): Add aarch64. + (libebl_pic): Add libebl_aarch64_pic.a. + (aarch64_SRCS): New variable. + (libebl_aarch64_pic_a_SOURCES): Likewise. + (am_libebl_aarch64_pic_a_OBJECTS): Likewise. + (aarch64_regs_no_Wformat): Likewise. + * aarch64_corenote.c, aarch64_init.c: New files. + * aarch64_regs.c, aarch64_reloc.def: Likewise. + * aarch64_retval.c, aarch64_symbol.c: Likewise. + * libebl_CPU.h (dwarf_peel_type): New function. + (dwarf_peeled_die_type): Likewise. + +2013-11-07 Jan Kratochvil <jan.kratochvil@redhat.com> + Mark Wielaard <mjw@redhat.com> + + * Makefile.am (i386_SRCS): Add i386_initreg.c. + (x86_64_SRCS): Add x86_64_initreg.c. + * i386_initreg.c: New file. + * i386_init.c (i386_init): Initialize frame_nregs and + set_initial_registers_tid. + * x86_64_initreg.c: New file. + * x86_64_init.c (x86_64_init): Initialize frame_nregs and + set_initial_registers_tid. + +2013-10-06 Mark Wielaard <mjw@redhat.com> + + * ppc_cfi.c (ppc_abi_cfi): Use DW_CFA_val_offset for reg1, not + DW_CFA_val_expression. + +2013-08-29 Mark Wielaard <mjw@redhat.com> + + * Makefile.am (arm_SRCS): Add arm_cfi.c. + * arm_cfi.c: New file. + * arm_init.c (arm_init): Initialize abi_cfi. + +2013-08-27 Jan Kratochvil <jan.kratochvil@redhat.com> + + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add ppc_cfi.c. + (s390_SRCS): Add s390_cfi.c. + * ppc64_init.c (ppc64_init): Initialize abi_cfi. + * ppc_cfi.c: New file. + * ppc_init.c (ppc_init): Initialize abi_cfi. + * s390_cfi.c: New file. + * s390_init.c (s390_init): Initialize abi_cfi. + +2013-08-28 Mark Wielaard <mjw@redhat.com> + + * arm_regs.c (arm_register_info): Set *prefix to "". + * ppc_regs.c (ppc_register_info): Likewise. + * sh_regs.c (sh_register_info): Likewise. + +2013-04-24 Mark Wielaard <mjw@redhat.com> + + * Makefile.am: Use AM_CPPFLAGS instead of INCLUDES. + +2013-02-06 Mark Wielaard <mjw@redhat.com> + + * libebl_CPU.h (DWARF_TAG_OR_RETURN): New macro. + * backends/alpha_retval.c (alpha_return_value_location): Use new + DWARF_TAG_OR_RETURN macro instead of dwarf_tag (). + * backends/arm_retval.c (arm_return_value_location): Likewise. + * backends/i386_retval.c (i386_return_value_location): Likewise. + * backends/ia64_retval.c (hfa_type): Likewise. + (ia64_return_value_location): Likewise. + * backends/ppc64_retval.c (ppc64_return_value_location): Likewise. + * backends/ppc_retval.c (ppc_return_value_location): Likewise. + * backends/s390_retval.c (s390_return_value_location): Likewise. + * backends/sh_retval.c (sh_return_value_location): Likewise. + * backends/sparc_retval.c (sparc_return_value_location): Likewise. + * backends/tilegx_retval.c (tilegx_return_value_location): Likewise. + * backends/x86_64_retval.c (x86_64_return_value_location): Likewise. + +2013-01-29 Jan Kratochvil <jan.kratochvil@redhat.com> + Roland McGrath <roland@hack.frob.com> + + * Makefile.am (s390_SRCS): Add s390_corenote.c and s390x_corenote.c. + * linux-core-note.c (ALIGN_PR_REG): New definitions. + (struct EBLHOOK(prstatus)): Change field pr_reg to anonymous struct with + ALIGN_PR_REG. + (EXTRA_ITEMS): New macro. + * s390_corenote.c: New file. + * s390_init.c (s390x_core_note): New declaration. + (s390_init): Install s390x_core_note and s390_core_note. + * s390x_corenote.c: New file. + +2013-01-30 Jan Kratochvil <jan.kratochvil@redhat.com> + + * arm_corenote.c (vfp_items): Remove zero COUNT initializer. + +2012-10-12 Jan Kratochvil <jan.kratochvil@redhat.com> + + * linux-core-note.c (prstatus_items): Rename groups of sigpend and + sighold to signal2 and signal3. + +2012-09-24 Petr Machata <pmachata@redhat.com> + + * arm_corenote.c (vfp_items, vfp_regs): New const variables. + (EXTRA_NOTES): Use it for NT_ARM_VFP. + * linux-core-note.c (EXTRA_REGSET_ITEMS): New macro. + +2012-09-17 Petr Machata <pmachata@redhat.com> + + * arm_corenote.c (FPREGSET_SIZE): Change to 116. + +2012-08-22 Jeff Kenton <jkenton@tilera.com> + + * Makefile.am (modules): Add tilegx. + (libebl_pic): Add libebl_tilegx_pic.a. + (tilegx_SRCS): New variable. + (libebl_tilegx_pic_a_SOURCES): Likewise. + (am_libebl_tilegx_pic_a_OBJECTS): Likewise. + * tilegx_corenote.c: New file. + * tilegx_regs.c: New file. + * tilegx_reloc.def: New file. + * tilegx_init.c: New file. + * tilegx_retval.c: New file. + * tilegx_symbol.c: New file. + +2011-03-09 Mark Wielaard <mjw@redhat.com> + + * alpha_init.c (alpha_init): Initialize check_st_other_bits hook. + * alpha_symbol.c (alpha_check_st_other_bits): New function. + +2011-03-09 Roland McGrath <roland@redhat.com> + + * alpha_symbol.c (alpha_check_special_symbol): New function. + * alpha_init.c (alpha_init): Initialize hook. + +2010-11-08 Roland McGrath <roland@redhat.com> + + * i386_retval.c (loc_intreg): Typo fix. + Reported by Thorsten Glaser <tg@mirbsd.de>. + +2010-04-10 Matt Fleming <matt@console-pimps.org> + + * sh_corenote.c: New file. + * sh_regs.c: New file. + * sh_retval.c: New file. + * sh_symbol.c (sh_machine_flag_check): New function. + * Makefile.am (sh_SRCS): Add new files. + * sh_init.c (sh_init): Add initializers. + +2010-04-07 Roland McGrath <roland@redhat.com> + + * arm_reloc.def: Accept PC24 and ABS32 in EXEC|DYN too. + +2010-03-04 Ulrich Drepper <drepper@redhat.com> + + * x86_64_reloc.def: Add entries for R_X86_64_SIZE32 and + R_X86_64_SIZE64. + +2010-02-18 Roland McGrath <roland@redhat.com> + + * Makefile.am (libebl_%.so): Use multi-target pattern rule instead of + intermediate dependency file for libebl_%.map, working around apparent + make -j timing-sensitive bugs. + +2010-02-15 Roland McGrath <roland@redhat.com> + + * Makefile.am: Use config/eu.am for common stuff. + +2010-01-05 Roland McGrath <roland@redhat.com> + + * arm_retval.c (arm_return_value_location): Use dwarf_aggregate_size. + * ia64_retval.c (ia64_return_value_location): Likewise. + * ppc_retval.c (ppc_return_value_location): Likewise. + * ppc64_retval.c (ppc64_return_value_location): Likewise. + * sparc_retval.c (sparc_return_value_location): Likewise. + + * ppc64_retval.c (ppc64_return_value_location): + Use vr2 for DW_TAG_array_type with DW_AT_GNU_vector. + * ppc_retval.c (ppc_return_value_location): Likewise. + +2010-01-04 Roland McGrath <roland@redhat.com> + + * linux-core-note.c (vmcoreinfo_items): New static const variable. + (EBLHOOK(core_note)): Update arguments for new protocol. + Validate the name as "CORE" or "LINUX" for known n_type cases. + Handle name "VMCOREINFO" n_type=0 with vmcoreinfo_items. + * i386_corenote.c (EXTRA_NOTES): Update parameter usage. + * x86_corenote.c (EXTRA_NOTES_IOPERM): Likewise. + +2009-09-10 Mark Wielaard <mjw@redhat.com> + + * sparc_retval.c: Fix license header. + +2009-08-07 Roland McGrath <roland@redhat.com> + + * x86_64_reloc.def: Add PC64, GOTOFF64, GOTPC32, GOTPC32_TLSDESC, + TLSDESC_CALL, TLSDESC. + +2009-07-08 Roland McGrath <roland@redhat.com> + + * x86_64_cfi.c (x86_64_abi_cfi): New file. + * Makefile.am (x86_64_SRCS): Add it. + * x86_64_init.c (x86_64_init): Add initializer. + + * i386_cfi.c (i386_abi_cfi): New file. + * Makefile.am (i386_SRCS): Add it. + * i386_init.c (i386_init): Initialize abi_cfi hook. + +2009-06-01 Ulrich Drepper <drepper@redhat.com> + + * i386_reloc.def: Add IRELATIVE entry. + * x86_64_reloc.def: Likewise. + +2009-04-16 Roland McGrath <roland@redhat.com> + + * arm_regs.c (arm_register_info): Handle VFP registers. + + * i386_corenote.c (EXTRA_NOTES): NT_PRXFPREG -> NT_PRXFPREG + +2009-04-14 Roland McGrath <roland@redhat.com> + + * arm_retval.c: New file. + * arm_attrs.c: New file. + * Makefile.am (arm_SRCS): Add them. + * arm_symbol.c (arm_segment_type_name): New function. + (arm_section_type_name): New function. + (arm_machine_flag_check): New function. + * arm_init.c (arm_init): Initialize those hooks. + + * arm_regs.c: New file. + * arm_corenote.c: New file. + * arm_auxv.c: New file. + * Makefile.am (arm_SRCS): Add them. + * arm_init.c (arm_init): Initialize core_note, register_info, + and auxv_info hooks. + + * ia64_symbol.c (ia64_section_type_name): Remove "SHT_" prefixes. + +2009-04-01 Roland McGrath <roland@redhat.com> + + * sparc_reloc.def: Update table. + Data from Dave Miller <davem@davemloft.net>. + +2009-02-15 Roland McGrath <roland@redhat.com> + + * ppc_attrs.c (ppc_check_object_attribute): Handle tag + GNU_Power_ABI_Struct_Return. + +2008-10-04 Ulrich Drepper <drepper@redhat.com> + + * i386_reloc.def: Fix entries for TLS_GOTDESC, TLS_DESC_CALL, and + TLS_DESC. + +2008-08-01 Roland McGrath <roland@redhat.com> + + * x86_corenote.c: New file. + * Makefile.am (noinst_HEADERS): Add it. + * i386_corenote.c: Include it, use EXTRA_NOTES_IOPERM in EXTRA_NOTES. + * x86_64_corenote.c: Likewise. + + * linux-core-note.c (prstatus_items): Use 'B' instead of 'b' + for sigpend and sighold. + +2008-07-04 Roland McGrath <roland@redhat.com> + + * i386_syscall.c: New file. + * x86_64_syscall.c: New file. + * ppc_syscall.c: New file. + * Makefile.am (i386_SRCS, x86_64_SRCS, ppc_SRCS, ppc64_SRCS): Add them. + * i386_init.c (i386_init): Initialize syscall_abi hook. + * x86_64_init.c (x86_64_init): Likewise. + * ppc_init.c (ppc_init): Likewise. + * ppc64_init.c (ppc64_init): Likewise. + + * ppc_corenote.c (PRSTATUS_REGSET_ITEMS): Add nip. + Fix offset calculation for 64-bit case. + +2008-04-04 Roland McGrath <roland@redhat.com> + + * alpha_symbol.c (alpha_check_special_section): New function. + * alpha_init.c (alpha_init): Initialize check_special_section hook. + +2008-03-31 Roland McGrath <roland@redhat.com> + + * sparc_symbol.c (sparc_symbol_type_name): New function. + (sparc_dynamic_tag_name): New function. + (sparc_dynamic_tag_check): New function. + * sparc_init.c (sparc_init): Initialize those hooks. + + * sparc_symbol.c (sparc_check_special_section): New function. + * sparc_init.c (sparc_init): Initialize check_special_section hook. + +2008-02-20 Roland McGrath <roland@redhat.com> + + * ppc_attrs.c: New file. + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add it. + * ppc_init.c (ppc_init): Initialize check_object_attribute hook. + +2008-02-14 Roland McGrath <roland@redhat.com> + + * alpha_auxv.c: New file. + * Makefile.am (alpha_SRCS): Add it. + * alpha_init.c (alpha_init): Initialize auxv_info hook. + +2008-02-08 Roland McGrath <roland@redhat.com> + + * ppc_corenote.c (spe_regs): New const variable. + (EXTRA_NOTES): Use it for NT_PPC_SPE. + +2008-01-02 Roland McGrath <roland@redhat.com> + + * i386_corenote.c (tls_items): New const table. + (tls_info): New function, uses it. + (EXTRA_NOTES): Use it to handle NT_386_TLS. + +2008-01-08 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am: Add x86-64 disassembler. + * x86_64_init.c (x86_64_init): Hook up disassembler. + +2007-12-28 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am: Add x86 disassembler. + * i386_init.c (i386_init): Hook up disassembler. + +2007-12-15 Roland McGrath <roland@redhat.com> + + * ppc_regs.c (ppc_register_info): Return "spefscr", not "spr512". + +2007-10-18 Roland McGrath <roland@redhat.com> + + * ppc_regs.c (ppc_register_info): Assign 67 to "vscr". + Return "vector" and 32 bits for vscr and vrsave. + * ppc_corenote.c (altivec_regs): New variable. + (EXTRA_NOTES): New macro, handle NT_PPC_VMX. + + * linux-core-note.c (EXTRA_REGSET): New macro. + Remove NT_PRXFPREG case. Instead, use EXTRA_NOTES if defined. + * i386_corenote.c (EXTRA_NOTES): Define it. + +2007-10-09 Roland McGrath <roland@redhat.com> + + * sparc_auxv.c: New file. + * Makefile.am (sparc_SRCS): Add it. + * sparc_init.c (sparc_init): Initialize auxv_info hook. + +2007-10-08 Roland McGrath <roland@redhat.com> + + * linux-core-note.c (TIMEVAL_FIELD): New macro. + (prstatus_items): Use it. + * sparc_corenote.c: New file. + * sparc64_corenote.c: New file. + * Makefile.am (sparc_SRCS): Add them. + * sparc_init.c (sparc_init): Initialize core_note hook. + + * sparc_symbol.c (sparc_machine_flag_check): New function. + * sparc_init.c (sparc_init): Use it. + +2007-09-27 Roland McGrath <roland@redhat.com> + + * alpha_retval.c: Use dwarf_attr_integrate and dwarf_hasattr_integrate. + * i386_retval.c: Likewise. + * ia64_retval.c: Likewise. + * ppc64_retval.c: Likewise. + * ppc_retval.c: Likewise. + * s390_retval.c: Likewise. + * sparc_retval.c: Likewise. + * x86_64_retval.c: Likewise. + +2007-10-31 Ulrich Drepper <drepper@redhat.com> + + * Makefile.am: More dependencies for the libebl_* libraries. + +2007-08-23 Roland McGrath <roland@redhat.com> + + * x86_64_regs.c (x86_64_register_info): Put %rflags in "integer" set. + +2007-08-22 Roland McGrath <roland@redhat.com> + + * linux-core-note.c (prstatus_items): Add .group initializers. + (prpsinfo_items): Likewise. + * x86_64_corenote.c (PRSTATUS_REGSET_ITEMS): Likewise. + * i386_corenote.c (PRSTATUS_REGSET_ITEMS): Likewise. + * ppc_corenote.c (PRSTATUS_REGSET_ITEMS): Likewise. + +2007-08-20 Roland McGrath <roland@redhat.com> + + * ppc_symbol.c (ppc_check_special_symbol): For _GLOBAL_OFFSET_TABLE_ + when DT_PPC_GOT is not found, anywhere in the section is valid. + +2007-08-19 Roland McGrath <roland@redhat.com> + + * i386_auxv.c: New file. + * Makefile.am (i386_SRCS, x86_64_SRCS): Add it. + * ppc_auxv.c: New file. + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add it. + * i386_init.c (i386_init): Initialize auxv_info hook. + * x86_64_init.c (x86_64_init): Likewise. + * ppc_init.c (ppc_init): Likewise. + * ppc64_init.c (ppc64_init): Likewise. + + * alpha_corenote.c: New file. + * Makefile.am (alpha_SRCS): Add it. + * alpha_init.c (alpha_init): Initialize core_note hook. + + * ppc_corenote.c: New file. + * ppc64_corenote.c: New file. + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add them. + * ppc_init.c (ppc_init): Initialize core_note hook. + * ppc64_init.c (ppc64_init): Likewise. + + * linux-core-note.c: New file. + * Makefile.am (noinst_HEADERS): Add it. + * i386_corenote.c: Rewritten. + * x86_64_corenote.c: Likewise. + +2007-05-23 Roland McGrath <roland@redhat.com> + + * alpha_regs.c (alpha_register_info): fp -> s6 + +2007-04-26 Roland McGrath <roland@redhat.com> + + * alpha_symbol.c (alpha_machine_section_flag_check): New function. + * alpha_init.c (alpha_init): Initialize hook. + + * alpha_regs.c: New file. + * Makefile.am (alpha_SRCS): Add it. + * alpha_init.c (alpha_init): Initialize register_info hook. + +2007-04-22 Roland McGrath <roland@redhat.com> + + * ppc_regs.c (ppc_register_info): Use some names instead of sprNNN: + mq, xer, lr, ctr, dsisr, dar, dec, vrsave. + Set *BITS to 64 for FPU registers. + + * i386_regs.c (i386_register_info): Set *BITS to 16 for fctrl, fstat. + * x86_64_regs.c (x86_64_register_info): Likewise for fcw, fsw. + +2007-04-01 Roland McGrath <roland@redhat.com> + + * x86_64_regs.c (x86_64_register_info): Add more registers from newer + ABI spec. + +2007-01-11 Roland McGrath <roland@redhat.com> + + * ia64_symbol.c (ia64_machine_section_flag_check): New function. + * ia64_init.c (ia64_init): Use it. + + * ia64_symbol.c (ia64_section_type_name): Typo fix in string. + +2006-10-09 Roland McGrath <roland@redhat.com> + + * ia64_symbol.c (ia64_reloc_simple_type): Treat SECREL types as simple. + +2006-08-29 Roland McGrath <roland@redhat.com> + + * sparc_retval.c: New file. + * Makefile.am (sparc_SRCS): Add it. + * sparc_init.c (sparc_init): Initialize return_value_location hook. + +2006-08-22 Roland McGrath <roland@redhat.com> + + * i386_regs.c (i386_register_name): Renamed i386_register_info. + Take new args, yield more info. + * i386_init.c (i386_init): Update initializer. + * ia64_regs.c (ia64_register_name): Likewise. + * ia64_init.c (ia64_init): Likewise. + * ppc_regs.c (ppc_register_name): Likewise. + * ppc64_init.c (ppc64_init): Likewise. + * ppc_init.c (ppc_init): Likewise. + * s390_regs.c (s390_register_name): Likewise. + * s390_init.c (s390_init): Likewise. + * sparc_regs.c (sparc_register_name): Likewise. + * sparc_init.c (sparc_init): Likewise. + * x86_64_regs.c (x86_64_register_name): Likewise. + * x86_64_init.c (x86_64_init): Likewise. + +2006-08-08 Roland McGrath <roland@redhat.com> + + * Makefile.am (%.os): Don't depend on %.o, since we don't actually + need static object for anything here. This rule is the only source of + .deps/ files. + +2006-06-23 Stepan Kasal <skasal@redhat.com> + + * Makefile.am (PACKAGE_VERSION): Remove superfluous definition. + +2006-08-03 Roland McGrath <roland@redhat.com> + + * sparc_regs.c (sparc_register_name): List 32 FPU regs only for + EM_SPARC. EM_SPARC32PLUS also has 64. + +2006-07-21 Roland McGrath <roland@redhat.com> + + * i386_regs.c (i386_register_name): Fix return value when using stpcpy. + * ppc_regs.c (ppc_register_name): Likewise. + * s390_regs.c (s390_register_name): Likewise. + + * ia64_retval.c: New file. + * Makefile.am (ia64_SRCS): Add it. + * ia64_init.c (ia64_init): Install return_value_location hook. + + * ia64_regs.c: New file. + * Makefile.am (ia64_SRCS): Add it. + * ia64_init.c (ia64_init): Install register_name hook. + +2006-07-05 Ulrich Drepper <drepper@redhat.com> + + * alpha_init.c: Initialize sysvhash_entrysize. + * s390_init.c: Likewise. + +2006-07-04 Ulrich Drepper <drepper@redhat.com> + + * common-reloc.c (relative_reloc_p): New function. + (init_reloc): Hook it up. + * ia64_reloc.def: Define NO_RELATIVE_RELOC. + +2006-06-13 Roland McGrath <roland@redhat.com> + + * ppc64_retval.c: Remove SVR4_STRUCT_RETURN braino. + +2006-06-12 Ulrich Drepper <drepper@redhat.com> + + * common-reloc.c (none_reloc_p): New function. + (init_reloc): Hook it up. + +2006-02-22 Roland McGrath <roland@redhat.com> + + * ppc64_retval.c (SVR4_STRUCT_RETURN): New macro. + (ppc64_return_value_location): Use registers for aggregate conditional + on that. + * ppc_retval.c (SVR4_STRUCT_RETURN): New macro. + (ppc_return_value_location): Use registers for aggregate conditional + on that. + +2006-01-12 Roland McGrath <roland@redhat.com> + + * s390_retval.c: New file. + * Makefile.am (s390_SRCS): Add it. + * s390_init.c (s390_init): Install return_value_location hook. + +2006-01-11 Roland McGrath <roland@redhat.com> + + * s390_regs.c: New file. + * Makefile.am (s390_SRCS): Add it. + * s390_init.c (s390_init): Install register_name hook. + + * s390_reloc.def: Update bits per + Martin Schwidefsky <schwidefsky@de.ibm.com>. + +2005-12-10 Ulrich Drepper + + * common-reloc.c (R_NAME): Generate string correctly. + +2005-12-05 Roland McGrath <roland@redhat.com> + + * i386_regs.c (i386_register_name): Use a table for the first 8 regs. + * x86_64_regs.c (x86_64_register_name): Likewise. + +2005-11-25 Roland McGrath <roland@redhat.com> + + * i386_regs.c (i386_register_name): Return 0, not 1, for gaps. + + * i386_regs.c: New file. + * ppc_regs.c: New file. + * sparc_regs.c: New file. + * x86_64_regs.c: New file. + * Makefile.am + (i386_SRCS, x86_64_SRCS, ppc_SRCS, ppc64_SRCS, sparc_SRCS): Add them. + * i386_init.c: Initialize register_name hook. + * ppc_init.c: Likewise. + * ppc64_init.c: Likewise. + * sparc_init.c: Likewise. + * x86_64_init.c: Likewise. + +2005-11-19 Roland McGrath <roland@redhat.com> + + * ppc64_reloc.def: REL30 -> ADDR30. + +2005-11-18 Roland McGrath <roland@redhat.com> + + * alpha_init.c: Use HOOK macro. + * arm_init.c: Likewise. + * i386_init.c: Likewise. + * ia64_init.c: Likewise. + * ppc64_init.c: Likewise. + * ppc_init.c: Likewise. + * s390_init.c: Likewise. + * sh_init.c: Likewise. + * sparc_init.c: Likewise. + * x86_64_init.c: Likewise. + +2005-11-17 Roland McGrath <roland@redhat.com> + + * Makefile.am (uninstall): Don't try to remove $(pkgincludedir). + (CLEANFILES): Add libebl_$(m).so. + + * ppc_reloc.def: Update bits per Alan Modra <amodra@bigpond.net.au>. + * ppc64_reloc.def: Likewise. + +2005-11-15 Roland McGrath <roland@redhat.com> + + * Contents moved here from ../libebl. diff --git a/backends/Makefile.am b/backends/Makefile.am new file mode 100644 index 00000000..687c089d --- /dev/null +++ b/backends/Makefile.am @@ -0,0 +1,148 @@ +## Process this file with automake to create Makefile.in +## +## Copyright (C) 2000-2010, 2013, 2014 Red Hat, Inc. +## Copyright (C) 2012 Tilera Corporation +## This file is part of elfutils. +## +## This file is free software; you can redistribute it and/or modify +## it under the terms of either +## +## * the GNU Lesser General Public License as published by the Free +## Software Foundation; either version 3 of the License, or (at +## your option) any later version +## +## or +## +## * the GNU General Public License as published by the Free +## Software Foundation; either version 2 of the License, or (at +## your option) any later version +## +## or both in parallel, as here. +## +## elfutils is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received copies of the GNU General Public License and +## the GNU Lesser General Public License along with this program. If +## not, see <http://www.gnu.org/licenses/>. +include $(top_srcdir)/config/eu.am +AM_CPPFLAGS += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \ + -I$(top_srcdir)/libelf -I$(top_srcdir)/libdw + + +modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \ + tilegx +libebl_pic = libebl_i386_pic.a libebl_sh_pic.a libebl_x86_64_pic.a \ + libebl_ia64_pic.a libebl_alpha_pic.a libebl_arm_pic.a \ + libebl_aarch64_pic.a libebl_sparc_pic.a libebl_ppc_pic.a \ + libebl_ppc64_pic.a libebl_s390_pic.a libebl_tilegx_pic.a +noinst_LIBRARIES = $(libebl_pic) +noinst_DATA = $(libebl_pic:_pic.a=.so) + + +libelf = ../libelf/libelf.so +libdw = ../libdw/libdw.so + +i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c i386_cfi.c \ + i386_retval.c i386_regs.c i386_auxv.c i386_syscall.c \ + i386_initreg.c +cpu_i386 = ../libcpu/libcpu_i386.a +libebl_i386_pic_a_SOURCES = $(i386_SRCS) +am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os) + +sh_SRCS = sh_init.c sh_symbol.c sh_corenote.c sh_regs.c sh_retval.c +libebl_sh_pic_a_SOURCES = $(sh_SRCS) +am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os) + +x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c x86_64_cfi.c \ + x86_64_retval.c x86_64_regs.c i386_auxv.c x86_64_syscall.c \ + x86_64_initreg.c +cpu_x86_64 = ../libcpu/libcpu_x86_64.a +libebl_x86_64_pic_a_SOURCES = $(x86_64_SRCS) +am_libebl_x86_64_pic_a_OBJECTS = $(x86_64_SRCS:.c=.os) + +ia64_SRCS = ia64_init.c ia64_symbol.c ia64_regs.c ia64_retval.c +libebl_ia64_pic_a_SOURCES = $(ia64_SRCS) +am_libebl_ia64_pic_a_OBJECTS = $(ia64_SRCS:.c=.os) + +alpha_SRCS = alpha_init.c alpha_symbol.c alpha_retval.c alpha_regs.c \ + alpha_corenote.c alpha_auxv.c +libebl_alpha_pic_a_SOURCES = $(alpha_SRCS) +am_libebl_alpha_pic_a_OBJECTS = $(alpha_SRCS:.c=.os) + +arm_SRCS = arm_init.c arm_symbol.c arm_regs.c arm_corenote.c \ + arm_auxv.c arm_attrs.c arm_retval.c arm_cfi.c arm_initreg.c +libebl_arm_pic_a_SOURCES = $(arm_SRCS) +am_libebl_arm_pic_a_OBJECTS = $(arm_SRCS:.c=.os) + +aarch64_SRCS = aarch64_init.c aarch64_regs.c aarch64_symbol.c \ + aarch64_corenote.c aarch64_retval.c aarch64_cfi.c \ + aarch64_initreg.c +libebl_aarch64_pic_a_SOURCES = $(aarch64_SRCS) +am_libebl_aarch64_pic_a_OBJECTS = $(aarch64_SRCS:.c=.os) + +sparc_SRCS = sparc_init.c sparc_symbol.c sparc_regs.c sparc_retval.c \ + sparc_corenote.c sparc64_corenote.c sparc_auxv.c +libebl_sparc_pic_a_SOURCES = $(sparc_SRCS) +am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os) + +ppc_SRCS = ppc_init.c ppc_symbol.c ppc_retval.c ppc_regs.c \ + ppc_corenote.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \ + ppc_cfi.c ppc_initreg.c +libebl_ppc_pic_a_SOURCES = $(ppc_SRCS) +am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os) + +ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \ + ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c ppc_syscall.c \ + ppc_cfi.c ppc_initreg.c ppc64_resolve_sym.c +libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS) +am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os) + +s390_SRCS = s390_init.c s390_symbol.c s390_regs.c s390_retval.c \ + s390_corenote.c s390x_corenote.c s390_cfi.c s390_initreg.c \ + s390_unwind.c +libebl_s390_pic_a_SOURCES = $(s390_SRCS) +am_libebl_s390_pic_a_OBJECTS = $(s390_SRCS:.c=.os) + +tilegx_SRCS = tilegx_init.c tilegx_symbol.c tilegx_regs.c \ + tilegx_retval.c tilegx_corenote.c +libebl_tilegx_pic_a_SOURCES = $(tilegx_SRCS) +am_libebl_tilegx_pic_a_OBJECTS = $(tilegx_SRCS:.c=.os) + + +libebl_%.so libebl_%.map: libebl_%_pic.a $(libelf) $(libdw) + @rm -f $(@:.so=.map) + echo 'ELFUTILS_$(PACKAGE_VERSION) { global: $*_init; local: *; };' \ + > $(@:.so=.map) + $(LINK) -shared -o $(@:.map=.so) \ + -Wl,--whole-archive $< $(cpu_$*) -Wl,--no-whole-archive \ + -Wl,--version-script,$(@:.so=.map) \ + -Wl,-z,defs -Wl,--as-needed $(libelf) $(libdw) + @$(textrel_check) + +libebl_i386.so: $(cpu_i386) +libebl_x86_64.so: $(cpu_x86_64) + +install: install-am install-ebl-modules +install-ebl-modules: + $(mkinstalldirs) $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) + for m in $(modules); do \ + $(INSTALL_PROGRAM) libebl_$${m}.so $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}-$(PACKAGE_VERSION).so; \ + ln -fs libebl_$${m}-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}.so; \ + done + +uninstall: uninstall-am + for m in $(modules); do \ + rm -f $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}-$(PACKAGE_VERSION).so; \ + rm -f $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR)/libebl_$${m}.so; \ + done + rmdir --ignore-fail-on-non-empty $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) + +noinst_HEADERS = libebl_CPU.h common-reloc.c linux-core-note.c x86_corenote.c +EXTRA_DIST = $(foreach m,$(modules),$($(m)_SRCS)) $(modules:=_reloc.def) + +CLEANFILES += $(foreach m,$(modules),\ + libebl_$(m).map libebl_$(m).so \ + $(am_libebl_$(m)_pic_a_OBJECTS)) diff --git a/backends/aarch64_cfi.c b/backends/aarch64_cfi.c new file mode 100644 index 00000000..acbb9b69 --- /dev/null +++ b/backends/aarch64_cfi.c @@ -0,0 +1,82 @@ +/* arm ABI-specified defaults for DWARF CFI. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + + +/* ABI-specified state of DWARF CFI based on: + + "DWARF for the ARM 64 bit architecture (AArch64) 1.0" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf + + "Procedure Call Standard for the ARM 64 bit Architecture 1.0" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf +*/ + +int +aarch64_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* The initial Canonical Frame Address is the value of the + Stack Pointer (r31) as setup in the previous frame. */ + DW_CFA_def_cfa, ULEB128_7 (30), ULEB128_7 (0), + +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + /* Callee-saved regs r19-r28. */ + SV (19), SV (20), SV (21), SV (22), SV (23), + SV (24), SV (25), SV (26), SV (27), SV (28), + + /* The Frame Pointer (FP, r29) and Link Register (LR, r30). */ + SV (29), SV (30), + + /* Callee-saved fpregs v8-v15. v0 == 64. */ + SV (72), SV (73), SV (74), SV (75), + SV (76), SV (77), SV (78), SV (79), +#undef SV + + /* XXX Note: registers intentionally unused by the program, + for example as a consequence of the procedure call standard + should be initialized as if by DW_CFA_same_value. */ + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = -4; + + abi_info->return_address_register = 30; /* lr. */ + + return 0; +} diff --git a/backends/aarch64_corenote.c b/backends/aarch64_corenote.c new file mode 100644 index 00000000..9b424859 --- /dev/null +++ b/backends/aarch64_corenote.c @@ -0,0 +1,163 @@ +/* AArch64 specific core note handling. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +#define ULONG uint64_t +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_ULONG 8 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#define PRSTATUS_REGS_SIZE (34 * 8) + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 32, .bits = 64 }, /* x0..x30, sp */ + }; + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "pc", .type = ELF_T_XWORD, .format = 'x', \ + .offset = (offsetof (struct EBLHOOK(prstatus), pr_reg) \ + + PRSTATUS_REGS_SIZE - 16), \ + .group = "register", \ + .pc_register = true \ + }, \ + { \ + .name = "pstate", .type = ELF_T_XWORD, .format = 'x', \ + .offset = (offsetof (struct EBLHOOK(prstatus), pr_reg) \ + + PRSTATUS_REGS_SIZE - 8), \ + .group = "register" \ + } + +static const Ebl_Register_Location aarch64_fpregset_regs[] = + { + { .offset = 0, .regno = 64, .count = 32, .bits = 128 }, /* v0..v31 */ + }; + +static const Ebl_Core_Item aarch64_fpregset_items[] = + { + { + .name = "fpsr", .type = ELF_T_WORD, .format = 'x', + .offset = 512, .group = "register" + }, + { + .name = "fpcr", .type = ELF_T_WORD, .format = 'x', + .offset = 516, .group = "register" + } + }; + +static const Ebl_Core_Item aarch64_tls_items[] = + { + { + .name = "tls", .type = ELF_T_XWORD, .format = 'x', + .offset = 0, .group = "register" + } + }; + +#define AARCH64_HWBP_REG(KIND, N) \ + { \ + .name = "DBG" KIND "VR" #N "_EL1", .type = ELF_T_XWORD, .format = 'x', \ + .offset = 8 + N * 16, .group = "register" \ + }, \ + { \ + .name = "DBG" KIND "CR" #N "_EL1", .type = ELF_T_WORD, .format = 'x', \ + .offset = 16 + N * 16, .group = "register" \ + } + +#define AARCH64_BP_WP_GROUP(KIND, NAME) \ + static const Ebl_Core_Item NAME[] = \ + { \ + { \ + .name = "dbg_info", .type = ELF_T_WORD, .format = 'x', \ + .offset = 0, .group = "control" \ + }, \ + /* N.B.: 4 bytes of padding here. */ \ + \ + AARCH64_HWBP_REG(KIND, 0), \ + AARCH64_HWBP_REG(KIND, 1), \ + AARCH64_HWBP_REG(KIND, 2), \ + AARCH64_HWBP_REG(KIND, 3), \ + AARCH64_HWBP_REG(KIND, 4), \ + AARCH64_HWBP_REG(KIND, 5), \ + AARCH64_HWBP_REG(KIND, 6), \ + AARCH64_HWBP_REG(KIND, 7), \ + AARCH64_HWBP_REG(KIND, 8), \ + AARCH64_HWBP_REG(KIND, 9), \ + AARCH64_HWBP_REG(KIND, 10), \ + AARCH64_HWBP_REG(KIND, 11), \ + AARCH64_HWBP_REG(KIND, 12), \ + AARCH64_HWBP_REG(KIND, 13), \ + AARCH64_HWBP_REG(KIND, 14), \ + AARCH64_HWBP_REG(KIND, 15), \ + \ + /* The DBGBVR+DBGBCR pair only takes 12 bytes. There are 4 bytes \ + of padding at the end of each pair. The item formatter in \ + readelf can skip those, but the missing 4 bytes at the end of \ + the whole block cause it to assume the whole item bunch \ + repeats, so it loops around to read more. Insert an explicit \ + (but invisible) padding word. */ \ + { \ + .name = "", .type = ELF_T_WORD, .format = 'h', \ + .offset = 260, .group = "register" \ + } \ + } + +AARCH64_BP_WP_GROUP ("B", aarch64_hw_bp_items); +AARCH64_BP_WP_GROUP ("W", aarch64_hw_wp_items); + +#undef AARCH64_BP_WP_GROUP +#undef AARCH64_HWBP_REG + +#define EXTRA_NOTES \ + EXTRA_REGSET_ITEMS (NT_FPREGSET, 528, \ + aarch64_fpregset_regs, aarch64_fpregset_items) \ + EXTRA_ITEMS (NT_ARM_TLS, 8, aarch64_tls_items) \ + EXTRA_ITEMS (NT_ARM_HW_BREAK, 264, aarch64_hw_bp_items) \ + EXTRA_ITEMS (NT_ARM_HW_WATCH, 264, aarch64_hw_wp_items) + +#include "linux-core-note.c" diff --git a/backends/aarch64_init.c b/backends/aarch64_init.c new file mode 100644 index 00000000..b0fd17a7 --- /dev/null +++ b/backends/aarch64_init.c @@ -0,0 +1,69 @@ +/* Initialization of AArch64 specific backend library. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND aarch64_ +#define RELOC_PREFIX R_AARCH64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on aarch64_reloc.def. */ +#include "common-reloc.c" + + +const char * +aarch64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "AARCH64"; + aarch64_init_reloc (eh); + HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, reloc_simple_type); + HOOK (eh, return_value_location); + HOOK (eh, check_special_symbol); + HOOK (eh, abi_cfi); + + /* X0-X30 (31 regs) + SP + 1 Reserved + ELR, 30 Reserved regs (34-43) + + V0-V31 (32 regs, least significant 64 bits only) + + ALT_FRAME_RETURN_COLUMN (used when LR isn't used) = 97 DWARF regs. */ + eh->frame_nregs = 97; + HOOK (eh, set_initial_registers_tid); + + return MODVERSION; +} diff --git a/backends/aarch64_initreg.c b/backends/aarch64_initreg.c new file mode 100644 index 00000000..9706205e --- /dev/null +++ b/backends/aarch64_initreg.c @@ -0,0 +1,92 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <assert.h> +#ifdef __aarch64__ +# include <linux/uio.h> +# include <sys/user.h> +# include <sys/ptrace.h> +/* Deal with old glibc defining user_pt_regs instead of user_regs_struct. */ +# ifndef HAVE_SYS_USER_REGS +# define user_regs_struct user_pt_regs +# define user_fpsimd_struct user_fpsimd_state +# endif +#endif + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +bool +aarch64_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __aarch64__ + return false; +#else /* __aarch64__ */ + + /* General registers. */ + struct user_regs_struct gregs; + struct iovec iovec; + iovec.iov_base = &gregs; + iovec.iov_len = sizeof (gregs); + if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec) != 0) + return false; + + /* X0..X30 plus SP. */ + if (! setfunc (0, 32, (Dwarf_Word *) &gregs.regs[0], arg)) + return false; + + /* PC. */ + if (! setfunc (-1, 1, (Dwarf_Word *) &gregs.pc, arg)) + return false; + + /* ELR cannot be found. */ + + /* FP registers (only 64bits are used). */ + struct user_fpsimd_struct fregs; + iovec.iov_base = &fregs; + iovec.iov_len = sizeof (fregs); + if (ptrace (PTRACE_GETREGSET, tid, NT_FPREGSET, &iovec) != 0) + return false; + + Dwarf_Word dwarf_fregs[32]; + for (int r = 0; r < 32; r++) + dwarf_fregs[r] = fregs.vregs[r] & 0xFFFFFFFF; + + if (! setfunc (64, 32, dwarf_fregs, arg)) + return false; + + return true; +#endif /* __aarch64__ */ +} diff --git a/backends/aarch64_regs.c b/backends/aarch64_regs.c new file mode 100644 index 00000000..7a8a6780 --- /dev/null +++ b/backends/aarch64_regs.c @@ -0,0 +1,102 @@ +/* Register names and numbers for AArch64 DWARF. + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <dwarf.h> +#include <stdarg.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +ssize_t +aarch64_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setnamep, + int *bits, int *typep) +{ + if (name == NULL) + return 128; + + __attribute__ ((format (printf, 3, 4))) + ssize_t + regtype (const char *setname, int type, const char *fmt, ...) + { + *setnamep = setname; + *typep = type; + + va_list ap; + va_start (ap, fmt); + int s = vsnprintf (name, namelen, fmt, ap); + va_end(ap); + + if (s < 0 || (unsigned) s >= namelen) + return -1; + return s + 1; + } + + *prefix = ""; + *bits = 64; + + switch (regno) + { + case 0 ... 30: + return regtype ("integer", DW_ATE_signed, "x%d", regno); + + case 31: + return regtype ("integer", DW_ATE_address, "sp"); + + case 32: + return 0; + + case 33: + return regtype ("integer", DW_ATE_address, "elr"); + + case 34 ... 63: + return 0; + + case 64 ... 95: + /* FP/SIMD register file supports a variety of data types--it + can be thought of as a register holding a single integer or + floating-point value, or a vector of 8-, 16-, 32- or 64-bit + integers. 128-bit quad-word is the only singular value that + covers the whole register, so mark the register thus. */ + *bits = 128; + return regtype ("FP/SIMD", DW_ATE_unsigned, "v%d", regno - 64); + + case 96 ... 127: + return 0; + + default: + return -1; + } +} diff --git a/backends/aarch64_reloc.def b/backends/aarch64_reloc.def new file mode 100644 index 00000000..36d29e65 --- /dev/null +++ b/backends/aarch64_reloc.def @@ -0,0 +1,157 @@ +/* List the relocation types for AArch64. -*- C -*- + Copyright (C) 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (ABS64, REL|EXEC|DYN) +RELOC_TYPE (ABS32, REL|EXEC|DYN) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JUMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (TLS_DTPMOD64, EXEC|DYN) +RELOC_TYPE (TLS_DTPREL64, EXEC|DYN) +RELOC_TYPE (TLS_TPREL64, EXEC|DYN) +RELOC_TYPE (TLSDESC, EXEC|DYN) + +/* R_AARCH64_NONE records that the section containing the place to be + relocated depends on the section defining the symbol mentioned in + the relocation directive[.] (ARM IHI 0056B). */ +RELOC_TYPE (NONE, REL) + +RELOC_TYPE (ABS16, REL) +RELOC_TYPE (PREL64, REL) +RELOC_TYPE (PREL32, REL) +RELOC_TYPE (PREL16, REL) +RELOC_TYPE (MOVW_UABS_G0, REL) +RELOC_TYPE (MOVW_UABS_G0_NC, REL) +RELOC_TYPE (MOVW_UABS_G1, REL) +RELOC_TYPE (MOVW_UABS_G1_NC, REL) +RELOC_TYPE (MOVW_UABS_G2, REL) +RELOC_TYPE (MOVW_UABS_G2_NC, REL) +RELOC_TYPE (MOVW_UABS_G3, REL) +RELOC_TYPE (MOVW_SABS_G0, REL) +RELOC_TYPE (MOVW_SABS_G1, REL) +RELOC_TYPE (MOVW_SABS_G2, REL) +RELOC_TYPE (LD_PREL_LO19, REL) +RELOC_TYPE (ADR_PREL_LO21, REL) +RELOC_TYPE (ADR_PREL_PG_HI21, REL) +RELOC_TYPE (ADR_PREL_PG_HI21_NC, REL) +RELOC_TYPE (ADD_ABS_LO12_NC, REL) +RELOC_TYPE (LDST8_ABS_LO12_NC, REL) +RELOC_TYPE (LDST16_ABS_LO12_NC, REL) +RELOC_TYPE (LDST32_ABS_LO12_NC, REL) +RELOC_TYPE (LDST64_ABS_LO12_NC, REL) +RELOC_TYPE (LDST128_ABS_LO12_NC, REL) +RELOC_TYPE (TSTBR14, REL) +RELOC_TYPE (CONDBR19, REL) +RELOC_TYPE (JUMP26, REL) +RELOC_TYPE (CALL26, REL) +RELOC_TYPE (MOVW_PREL_G0, REL) +RELOC_TYPE (MOVW_PREL_G0_NC, REL) +RELOC_TYPE (MOVW_PREL_G1, REL) +RELOC_TYPE (MOVW_PREL_G1_NC, REL) +RELOC_TYPE (MOVW_PREL_G2, REL) +RELOC_TYPE (MOVW_PREL_G2_NC, REL) +RELOC_TYPE (MOVW_PREL_G3, REL) +RELOC_TYPE (MOVW_GOTOFF_G0, REL) +RELOC_TYPE (MOVW_GOTOFF_G0_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G1, REL) +RELOC_TYPE (MOVW_GOTOFF_G1_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G2, REL) +RELOC_TYPE (MOVW_GOTOFF_G2_NC, REL) +RELOC_TYPE (MOVW_GOTOFF_G3, REL) +RELOC_TYPE (GOTREL64, REL) +RELOC_TYPE (GOTREL32, REL) +RELOC_TYPE (GOT_LD_PREL19, REL) +RELOC_TYPE (LD64_GOTOFF_LO15, REL) +RELOC_TYPE (ADR_GOT_PAGE, REL) +RELOC_TYPE (LD64_GOT_LO12_NC, REL) +RELOC_TYPE (LD64_GOTPAGE_LO15, REL) +RELOC_TYPE (TLSGD_ADR_PREL21, REL) +RELOC_TYPE (TLSGD_ADR_PAGE21, REL) +RELOC_TYPE (TLSGD_ADD_LO12_NC, REL) +RELOC_TYPE (TLSGD_MOVW_G1, REL) +RELOC_TYPE (TLSGD_MOVW_G0_NC, REL) +RELOC_TYPE (TLSLD_ADR_PREL21, REL) +RELOC_TYPE (TLSLD_ADR_PAGE21, REL) +RELOC_TYPE (TLSLD_ADD_LO12_NC, REL) +RELOC_TYPE (TLSLD_MOVW_G1, REL) +RELOC_TYPE (TLSLD_MOVW_G0_NC, REL) +RELOC_TYPE (TLSLD_LD_PREL19, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G2, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G1, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G1_NC, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G0, REL) +RELOC_TYPE (TLSLD_MOVW_DTPREL_G0_NC, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_HI12, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_ADD_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST8_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST8_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST16_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST16_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST32_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST32_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST64_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST64_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSLD_LDST128_DTPREL_LO12, REL) +RELOC_TYPE (TLSLD_LDST128_DTPREL_LO12_NC, REL) +RELOC_TYPE (TLSIE_MOVW_GOTTPREL_G1, REL) +RELOC_TYPE (TLSIE_MOVW_GOTTPREL_G0_NC, REL) +RELOC_TYPE (TLSIE_ADR_GOTTPREL_PAGE21, REL) +RELOC_TYPE (TLSIE_LD64_GOTTPREL_LO12_NC, REL) +RELOC_TYPE (TLSIE_LD_GOTTPREL_PREL19, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G2, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G1, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G1_NC, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G0, REL) +RELOC_TYPE (TLSLE_MOVW_TPREL_G0_NC, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_HI12, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_ADD_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST8_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST8_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST16_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST16_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST32_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST32_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST64_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST64_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSLE_LDST128_TPREL_LO12, REL) +RELOC_TYPE (TLSLE_LDST128_TPREL_LO12_NC, REL) +RELOC_TYPE (TLSDESC_LD_PREL19, REL) +RELOC_TYPE (TLSDESC_ADR_PREL21, REL) +RELOC_TYPE (TLSDESC_ADR_PAGE21, REL) +RELOC_TYPE (TLSDESC_LD64_LO12, REL) +RELOC_TYPE (TLSDESC_ADD_LO12, REL) +RELOC_TYPE (TLSDESC_OFF_G1, REL) +RELOC_TYPE (TLSDESC_OFF_G0_NC, REL) +RELOC_TYPE (TLSDESC_LDR, REL) +RELOC_TYPE (TLSDESC_ADD, REL) +RELOC_TYPE (TLSDESC_CALL, REL) diff --git a/backends/aarch64_retval.c b/backends/aarch64_retval.c new file mode 100644 index 00000000..68de307e --- /dev/null +++ b/backends/aarch64_retval.c @@ -0,0 +1,376 @@ +/* Function return value location for Linux/AArch64 ABI. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <inttypes.h> + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + +static int +skip_until (Dwarf_Die *child, int tag) +{ + int i; + while (DWARF_TAG_OR_RETURN (child) != tag) + if ((i = dwarf_siblingof (child, child)) != 0) + /* If there are no members, then this is not a HFA. Errors + are propagated. */ + return i; + return 0; +} + +static int +dwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep) +{ + int bits; + if (((bits = 8 * dwarf_bytesize (die)) < 0 + && (bits = dwarf_bitsize (die)) < 0) + || bits % 8 != 0) + return -1; + + *sizep = bits / 8; + return 0; +} + +/* HFA (Homogeneous Floating-point Aggregate) is an aggregate type + whose members are all of the same floating-point type, which is + then base type of this HFA. Instead of being floating-point types + directly, members can instead themselves be HFA. Such HFA fields + are handled as if their type were HFA base type. + + This function returns 0 if TYPEDIE is HFA, 1 if it is not, or -1 if + there were errors. In the former case, *SIZEP contains byte size + of the base type (e.g. 8 for IEEE double). *COUNT is set to the + number of leaf members of the HFA. */ +static int hfa_type (Dwarf_Die *ftypedie, int tag, + Dwarf_Word *sizep, Dwarf_Word *countp); + +/* Return 0 if MEMBDIE refers to a member with a floating-point or HFA + type, or 1 if it's not. Return -1 for errors. The meaning of the + remaining arguments is as documented at hfa_type. */ +static int +member_is_fp (Dwarf_Die *membdie, Dwarf_Word *sizep, Dwarf_Word *countp) +{ + Dwarf_Die typedie; + int tag = dwarf_peeled_die_type (membdie, &typedie); + switch (tag) + { + case DW_TAG_base_type:; + Dwarf_Word encoding; + Dwarf_Attribute attr_mem; + if (dwarf_attr_integrate (&typedie, DW_AT_encoding, &attr_mem) == NULL + || dwarf_formudata (&attr_mem, &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_complex_float: + *countp = 2; + break; + + case DW_ATE_float: + *countp = 1; + break; + + default: + return 1; + } + + if (dwarf_bytesize_aux (&typedie, sizep) < 0) + return -1; + + *sizep /= *countp; + return 0; + + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + return hfa_type (&typedie, tag, sizep, countp); + } + + return 1; +} + +static int +hfa_type (Dwarf_Die *ftypedie, int tag, Dwarf_Word *sizep, Dwarf_Word *countp) +{ + assert (tag == DW_TAG_structure_type || tag == DW_TAG_class_type + || tag == DW_TAG_union_type || tag == DW_TAG_array_type); + + int i; + if (tag == DW_TAG_array_type) + { + Dwarf_Word tot_size; + if (dwarf_aggregate_size (ftypedie, &tot_size) < 0) + return -1; + + /* For vector types, we don't care about the underlying + type, but only about the vector type itself. */ + bool vec; + Dwarf_Attribute attr_mem; + if (dwarf_formflag (dwarf_attr_integrate (ftypedie, DW_AT_GNU_vector, + &attr_mem), &vec) == 0 + && vec) + { + *sizep = tot_size; + *countp = 1; + + return 0; + } + + if ((i = member_is_fp (ftypedie, sizep, countp)) == 0) + { + *countp = tot_size / *sizep; + return 0; + } + + return i; + } + + /* Find first DW_TAG_member and determine its type. */ + Dwarf_Die member; + if ((i = dwarf_child (ftypedie, &member) != 0)) + return i; + + if ((i = skip_until (&member, DW_TAG_member)) != 0) + return i; + + *countp = 0; + if ((i = member_is_fp (&member, sizep, countp)) != 0) + return i; + + while ((i = dwarf_siblingof (&member, &member)) == 0 + && (i = skip_until (&member, DW_TAG_member)) == 0) + { + Dwarf_Word size, count; + if ((i = member_is_fp (&member, &size, &count)) != 0) + return i; + + if (*sizep != size) + return 1; + + *countp += count; + } + + /* At this point we already have at least one FP member, which means + FTYPEDIE is an HFA. So either return 0, or propagate error. */ + return i < 0 ? i : 0; +} + +static int +pass_in_gpr (const Dwarf_Op **locp, Dwarf_Word size) +{ + static const Dwarf_Op loc[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 } + }; + + *locp = loc; + return size <= 8 ? 1 : 4; +} + +static int +pass_by_ref (const Dwarf_Op **locp) +{ + static const Dwarf_Op loc[] = { { .atom = DW_OP_breg0 } }; + + *locp = loc; + return 1; +} + +static int +pass_hfa (const Dwarf_Op **locp, Dwarf_Word size, Dwarf_Word count) +{ + assert (count >= 1 && count <= 4); + assert (size == 2 || size == 4 || size == 8 || size == 16); + +#define DEFINE_FPREG(NAME, SIZE) \ + static const Dwarf_Op NAME[] = { \ + { .atom = DW_OP_regx, .number = 64 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 65 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 66 }, \ + { .atom = DW_OP_piece, .number = SIZE }, \ + { .atom = DW_OP_regx, .number = 67 }, \ + { .atom = DW_OP_piece, .number = SIZE } \ + } + + switch (size) + { + case 2:; + DEFINE_FPREG (loc_hfa_2, 2); + *locp = loc_hfa_2; + break; + + case 4:; + DEFINE_FPREG (loc_hfa_4, 4); + *locp = loc_hfa_4; + break; + + case 8:; + DEFINE_FPREG (loc_hfa_8, 8); + *locp = loc_hfa_8; + break; + + case 16:; + DEFINE_FPREG (loc_hfa_16, 16); + *locp = loc_hfa_16; + break; + } +#undef DEFINE_FPREG + + return count == 1 ? 1 : 2 * count; +} + +static int +pass_in_simd (const Dwarf_Op **locp) +{ + /* This is like passing single-element HFA. Size doesn't matter, so + pretend it's for example double. */ + return pass_hfa (locp, 8, 1); +} + +int +aarch64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die typedie; + int tag = dwarf_peeled_die_type (functypedie, &typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size = (Dwarf_Word)-1; + + /* If the argument type is a Composite Type that is larger than 16 + bytes, then the argument is copied to memory allocated by the + caller and the argument is replaced by a pointer to the copy. */ + if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type + || tag == DW_TAG_class_type || tag == DW_TAG_array_type) + { + Dwarf_Word base_size, count; + switch (hfa_type (&typedie, tag, &base_size, &count)) + { + default: + return -1; + + case 0: + assert (count > 0); + if (count <= 4) + return pass_hfa (locp, base_size, count); + /* Fall through. */ + + case 1: + /* Not a HFA. */ + if (dwarf_aggregate_size (&typedie, &size) < 0) + return -1; + if (size > 16) + return pass_by_ref (locp); + } + } + + if (tag == DW_TAG_base_type + || tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + { + if (dwarf_bytesize_aux (&typedie, &size) < 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + + Dwarf_Attribute attr_mem; + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (&typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + switch (encoding) + { + /* If the argument is a Half-, Single-, Double- or Quad- + precision Floating-point [...] the argument is allocated + to the least significant bits of register v[NSRN]. */ + case DW_ATE_float: + switch (size) + { + case 2: /* half */ + case 4: /* sigle */ + case 8: /* double */ + case 16: /* quad */ + return pass_in_simd (locp); + + default: + return -2; + } + + case DW_ATE_complex_float: + switch (size) + { + case 8: /* float _Complex */ + case 16: /* double _Complex */ + case 32: /* long double _Complex */ + return pass_hfa (locp, size / 2, 2); + + default: + return -2; + } + + /* If the argument is an Integral or Pointer Type, the + size of the argument is less than or equal to 8 bytes + [...] the argument is copied to the least significant + bits in x[NGRN]. */ + case DW_ATE_boolean: + case DW_ATE_signed: + case DW_ATE_unsigned: + case DW_ATE_unsigned_char: + case DW_ATE_signed_char: + return pass_in_gpr (locp, size); + } + + return -2; + } + else + return pass_in_gpr (locp, size); + } + + *locp = NULL; + return 0; +} diff --git a/backends/aarch64_symbol.c b/backends/aarch64_symbol.c new file mode 100644 index 00000000..3fdc9cf8 --- /dev/null +++ b/backends/aarch64_symbol.c @@ -0,0 +1,87 @@ +/* AArch64 specific symbolic name handling. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND aarch64_ +#include "libebl_CPU.h" + + +/* Check for the simple reloc types. */ +Elf_Type +aarch64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_AARCH64_ABS64: + return ELF_T_XWORD; + case R_AARCH64_ABS32: + return ELF_T_WORD; + case R_AARCH64_ABS16: + return ELF_T_HALF; + + default: + return ELF_T_NUM; + } +} + +/* If this is the _GLOBAL_OFFSET_TABLE_ symbol, then it should point to + .got[0] even if there is a .got.plt section. */ +bool +aarch64_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym, + const char *name, const GElf_Shdr *destshdr) +{ + if (name != NULL + && strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + { + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname != NULL && strcmp (sname, ".got.plt") == 0) + { + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + if (shdr != NULL) + { + sname = elf_strptr (elf, ehdr->e_shstrndx, shdr->sh_name); + if (sname != NULL && strcmp (sname, ".got") == 0) + return sym->st_value == shdr->sh_addr; + } + } + } + } + + return false; +} diff --git a/backends/alpha_auxv.c b/backends/alpha_auxv.c new file mode 100644 index 00000000..83e71997 --- /dev/null +++ b/backends/alpha_auxv.c @@ -0,0 +1,49 @@ +/* Alpha-specific auxv handling. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND alpha_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "bwx\0" "fix\0" "cix\0" "0x08\0" + "0x10\0" "0x20\0" "0x40\0" "0x80\0" + "max\0" "precise_trap\0" + "\0"; + return 1; +} diff --git a/backends/alpha_corenote.c b/backends/alpha_corenote.c new file mode 100644 index 00000000..6190df37 --- /dev/null +++ b/backends/alpha_corenote.c @@ -0,0 +1,70 @@ +/* PowerPC specific core note handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND alpha_ +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 31, .bits = 64 }, /* r0-r30 */ + { .offset = 32 * 8, .regno = 64, .count = 1, .bits = 64 }, /* pc */ + { .offset = 33 * 8, .regno = 66, .count = 1, .bits = 64 }, /* unique */ + }; +#define PRSTATUS_REGS_SIZE (33 * 8) + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 32, .count = 32, .bits = 64 }, /* f0-f30, fpcr */ + }; +#define FPREGSET_SIZE (32 * 8) + +#define ULONG uint64_t +#define ALIGN_ULONG 8 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_LONG ELF_T_SXWORD +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#include "linux-core-note.c" diff --git a/backends/alpha_init.c b/backends/alpha_init.c new file mode 100644 index 00000000..a3307d83 --- /dev/null +++ b/backends/alpha_init.c @@ -0,0 +1,70 @@ +/* Initialization of Alpha specific backend library. + Copyright (C) 2002-2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND alpha_ +#define RELOC_PREFIX R_ALPHA_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on alpha_reloc.def. */ +#include "common-reloc.c" + + +const char * +alpha_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Alpha"; + alpha_init_reloc (eh); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, reloc_simple_type); + HOOK (eh, return_value_location); + HOOK (eh, machine_section_flag_check); + HOOK (eh, check_special_section); + HOOK (eh, check_special_symbol); + HOOK (eh, check_st_other_bits); + HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, auxv_info); + eh->sysvhash_entrysize = sizeof (Elf64_Xword); + + return MODVERSION; +} diff --git a/backends/alpha_regs.c b/backends/alpha_regs.c new file mode 100644 index 00000000..436af3b1 --- /dev/null +++ b/backends/alpha_regs.c @@ -0,0 +1,164 @@ +/* Register names and numbers for Alpha DWARF. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND alpha_ +#include "libebl_CPU.h" + +ssize_t +alpha_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 67; + + if (regno < 0 || regno > 66 || namelen < 7) + return -1; + + *prefix = "$"; + + *bits = 64; + *type = DW_ATE_signed; + *setname = "integer"; + if (regno >= 32 && regno < 64) + { + *setname = "FPU"; + *type = DW_ATE_float; + } + + switch (regno) + { + case 0: + name[0] = 'v'; + name[1] = '0'; + namelen = 2; + break; + + case 1 ... 8: + name[0] = 't'; + name[1] = regno - 1 + '0'; + namelen = 2; + break; + + case 9 ... 15: + name[0] = 's'; + name[1] = regno - 9 + '0'; + namelen = 2; + break; + + case 16 ... 21: + name[0] = 'a'; + name[1] = regno - 16 + '0'; + namelen = 2; + break; + + case 22 ... 23: + name[0] = 't'; + name[1] = regno - 22 + '8'; + namelen = 2; + break; + + case 24 ... 25: + name[0] = 't'; + name[1] = '1'; + name[2] = regno - 24 + '0'; + namelen = 3; + break; + + case 26: + *type = DW_ATE_address; + return stpcpy (name, "ra") + 1 - name; + + case 27: + return stpcpy (name, "t12") + 1 - name; + + case 28: + return stpcpy (name, "at") + 1 - name; + + case 29: + *type = DW_ATE_address; + return stpcpy (name, "gp") + 1 - name; + + case 30: + *type = DW_ATE_address; + return stpcpy (name, "sp") + 1 - name; + + case 31: + return stpcpy (name, "zero") + 1 - name; + + case 32 ... 32 + 9: + name[0] = 'f'; + name[1] = regno - 32 + '0'; + namelen = 2; + break; + + case 32 + 10 ... 32 + 19: + name[0] = 'f'; + name[1] = '1'; + name[2] = regno - 32 - 10 + '0'; + namelen = 3; + break; + + case 32 + 20 ... 32 + 29: + name[0] = 'f'; + name[1] = '2'; + name[2] = regno - 32 - 20 + '0'; + namelen = 3; + break; + + case 32 + 30: + return stpcpy (name, "f30") + 1 - name; + + case 32 + 31: + *type = DW_ATE_unsigned; + return stpcpy (name, "fpcr") + 1 - name; + + case 64: + *type = DW_ATE_address; + return stpcpy (name, "pc") + 1 - name; + + case 66: + *type = DW_ATE_address; + return stpcpy (name, "unique") + 1 - name; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/alpha_reloc.def b/backends/alpha_reloc.def new file mode 100644 index 00000000..ed7e5c32 --- /dev/null +++ b/backends/alpha_reloc.def @@ -0,0 +1,63 @@ +/* List the relocation types for alpha. -*- C -*- + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (REFLONG, REL|EXEC|DYN) +RELOC_TYPE (REFQUAD, REL|EXEC|DYN) +RELOC_TYPE (GPREL32, REL) +RELOC_TYPE (LITERAL, REL) +RELOC_TYPE (LITUSE, REL) +RELOC_TYPE (GPDISP, REL) +RELOC_TYPE (BRADDR, REL) +RELOC_TYPE (HINT, REL) +RELOC_TYPE (SREL16, REL) +RELOC_TYPE (SREL32, REL) +RELOC_TYPE (SREL64, REL) +RELOC_TYPE (GPRELHIGH, REL) +RELOC_TYPE (GPRELLOW, REL) +RELOC_TYPE (GPREL16, REL) +RELOC_TYPE (COPY, 0) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (TLS_GD_HI, REL) +RELOC_TYPE (TLSGD, REL) +RELOC_TYPE (TLS_LDM, REL) +RELOC_TYPE (DTPMOD64, REL|EXEC|DYN) +RELOC_TYPE (GOTDTPREL, REL) +RELOC_TYPE (DTPREL64, REL|EXEC|DYN) +RELOC_TYPE (DTPRELHI, REL) +RELOC_TYPE (DTPRELLO, REL) +RELOC_TYPE (DTPREL16, REL) +RELOC_TYPE (GOTTPREL, REL) +RELOC_TYPE (TPREL64, REL|EXEC|DYN) +RELOC_TYPE (TPRELHI, REL) +RELOC_TYPE (TPRELLO, REL) +RELOC_TYPE (TPREL16, REL) diff --git a/backends/alpha_retval.c b/backends/alpha_retval.c new file mode 100644 index 00000000..53dbfa45 --- /dev/null +++ b/backends/alpha_retval.c @@ -0,0 +1,150 @@ +/* Function return value location for Alpha ELF ABI. + Copyright (C) 2005, 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND alpha_ +#include "libebl_CPU.h" + + +/* $0. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 } + }; +#define nloc_intreg 1 + +/* $f0, or pair $f0, $f1. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_fpreg 1 +#define nloc_fpregpair 4 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in $0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + +int +alpha_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + Dwarf_Word size; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + *locp = loc_fpreg; + if (encoding == DW_ATE_float) + { + if (size <= 8) + return nloc_fpreg; + goto aggregate; + } + if (encoding == DW_ATE_complex_float) + { + if (size <= 8 * 2) + return nloc_fpregpair; + goto aggregate; + } + } + if (size <= 8) + { + *locp = loc_intreg; + return nloc_intreg; + } + } + + /* Else fall through. */ + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_string_type: + case DW_TAG_array_type: + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/alpha_symbol.c b/backends/alpha_symbol.c new file mode 100644 index 00000000..657d9eec --- /dev/null +++ b/backends/alpha_symbol.c @@ -0,0 +1,156 @@ +/* Alpha specific symbolic name handling. + Copyright (C) 2002-2011 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND alpha_ +#include "libebl_CPU.h" + + +const char * +alpha_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_ALPHA_PLTRO: + return "ALPHA_PLTRO"; + default: + break; + } + return NULL; +} + +bool +alpha_dynamic_tag_check (int64_t tag) +{ + return tag == DT_ALPHA_PLTRO; +} + +/* Check for the simple reloc types. */ +Elf_Type +alpha_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_ALPHA_REFLONG: + return ELF_T_WORD; + case R_ALPHA_REFQUAD: + return ELF_T_XWORD; + default: + return ELF_T_NUM; + } +} + + +/* Check whether SHF_MASKPROC flags are valid. */ +bool +alpha_machine_section_flag_check (GElf_Xword sh_flags) +{ + return (sh_flags &~ (SHF_ALPHA_GPREL)) == 0; +} + +bool +alpha_check_special_section (Ebl *ebl, + int ndx __attribute__ ((unused)), + const GElf_Shdr *shdr, + const char *sname __attribute__ ((unused))) +{ + if ((shdr->sh_flags + & (SHF_WRITE | SHF_EXECINSTR)) == (SHF_WRITE | SHF_EXECINSTR) + && shdr->sh_addr != 0) + { + /* This is ordinarily flagged, but is valid for an old-style PLT. + + Look for the SHT_DYNAMIC section and the DT_PLTGOT tag in it. + Its d_ptr should match the .plt section's sh_addr. */ + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr scn_shdr; + if (likely (gelf_getshdr (scn, &scn_shdr) != NULL) + && scn_shdr.sh_type == SHT_DYNAMIC + && scn_shdr.sh_entsize != 0) + { + GElf_Addr pltgot = 0; + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL) + for (size_t i = 0; i < data->d_size / scn_shdr.sh_entsize; ++i) + { + GElf_Dyn dyn; + if (unlikely (gelf_getdyn (data, i, &dyn) == NULL)) + break; + if (dyn.d_tag == DT_PLTGOT) + pltgot = dyn.d_un.d_ptr; + else if (dyn.d_tag == DT_ALPHA_PLTRO && dyn.d_un.d_val != 0) + return false; /* This PLT should not be writable. */ + } + return pltgot == shdr->sh_addr; + } + } + } + + return false; +} + +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +bool +alpha_check_special_symbol (Elf *elf __attribute__ ((unused)), + GElf_Ehdr *ehdr __attribute__ ((unused)), + const GElf_Sym *sym __attribute__ ((unused)), + const char *name, + const GElf_Shdr *destshdr __attribute__ ((unused))) +{ + if (name == NULL) + return false; + + if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + /* On Alpha any place in the section is valid. */ + return true; + + return false; +} + +/* Check whether only valid bits are set on the st_other symbol flag. + Standard ST_VISIBILITY have already been masked off. */ +bool +alpha_check_st_other_bits (unsigned char st_other) +{ + return ((((st_other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_NOPV) + || ((st_other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_STD_GPLOAD)) + && (st_other &~ STO_ALPHA_STD_GPLOAD) == 0); +} diff --git a/backends/arm_attrs.c b/backends/arm_attrs.c new file mode 100644 index 00000000..c858715d --- /dev/null +++ b/backends/arm_attrs.c @@ -0,0 +1,245 @@ +/* Object attribute tags for ARM. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + +#define KNOWN_VALUES(...) do \ + { \ + static const char *table[] = { __VA_ARGS__ }; \ + if (value < sizeof table / sizeof table[0]) \ + *value_name = table[value]; \ + } while (0) + +bool +arm_check_object_attribute (ebl, vendor, tag, value, tag_name, value_name) + Ebl *ebl __attribute__ ((unused)); + const char *vendor; + int tag; + uint64_t value __attribute__ ((unused)); + const char **tag_name; + const char **value_name; +{ + if (!strcmp (vendor, "aeabi")) + switch (tag) + { + case 4: + *tag_name = "CPU_raw_name"; + return true; + case 5: + *tag_name = "CPU_name"; + return true; + case 6: + *tag_name = "CPU_arch"; + KNOWN_VALUES ("Pre-v4", + "v4", + "v4T", + "v5T", + "v5TE", + "v5TEJ", + "v6", + "v6KZ", + "v6T2", + "v6K", + "v7", + "v6-M", + "v6S-M"); + return true; + case 7: + *tag_name = "CPU_arch_profile"; + switch (value) + { + case 'A': + *value_name = "Application"; + break; + case 'R': + *value_name = "Realtime"; + break; + case 'M': + *value_name = "Microcontroller"; + break; + } + return true; + case 8: + *tag_name = "ARM_ISA_use"; + KNOWN_VALUES ("No", "Yes"); + return true; + case 9: + *tag_name = "THUMB_ISA_use"; + KNOWN_VALUES ("No", "Thumb-1", "Thumb-2"); + return true; + case 10: + *tag_name = "VFP_arch"; + KNOWN_VALUES ("No", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16"); + return true; + case 11: + *tag_name = "WMMX_arch"; + KNOWN_VALUES ("No", "WMMXv1", "WMMXv2"); + return true; + case 12: + *tag_name = "Advanced_SIMD_arch"; + KNOWN_VALUES ("No", "NEONv1"); + return true; + case 13: + *tag_name = "PCS_config"; + KNOWN_VALUES ("None", + "Bare platform", + "Linux application", + "Linux DSO", + "PalmOS 2004", + "PalmOS (reserved)", + "SymbianOS 2004", + "SymbianOS (reserved)"); + return true; + case 14: + *tag_name = "ABI_PCS_R9_use"; + KNOWN_VALUES ("V6", "SB", "TLS", "Unused"); + return true; + case 15: + *tag_name = "ABI_PCS_RW_data"; + KNOWN_VALUES ("Absolute", "PC-relative", "SB-relative", "None"); + return true; + case 16: + *tag_name = "ABI_PCS_RO_data"; + KNOWN_VALUES ("Absolute", "PC-relative", "None"); + return true; + case 17: + *tag_name = "ABI_PCS_GOT_use"; + KNOWN_VALUES ("None", "direct", "GOT-indirect"); + return true; + case 18: + *tag_name = "ABI_PCS_wchar_t"; + return true; + case 19: + *tag_name = "ABI_FP_rounding"; + KNOWN_VALUES ("Unused", "Needed"); + return true; + case 20: + *tag_name = "ABI_FP_denormal"; + KNOWN_VALUES ("Unused", "Needed", "Sign only"); + return true; + case 21: + *tag_name = "ABI_FP_exceptions"; + KNOWN_VALUES ("Unused", "Needed"); + return true; + case 22: + *tag_name = "ABI_FP_user_exceptions"; + KNOWN_VALUES ("Unused", "Needed"); + return true; + case 23: + *tag_name = "ABI_FP_number_model"; + KNOWN_VALUES ("Unused", "Finite", "RTABI", "IEEE 754"); + return true; + case 24: + *tag_name = "ABI_align8_needed"; + KNOWN_VALUES ("No", "Yes", "4-byte"); + return true; + case 25: + *tag_name = "ABI_align8_preserved"; + KNOWN_VALUES ("No", "Yes, except leaf SP", "Yes"); + return true; + case 26: + *tag_name = "ABI_enum_size"; + KNOWN_VALUES ("Unused", "small", "int", "forced to int"); + return true; + case 27: + *tag_name = "ABI_HardFP_use"; + KNOWN_VALUES ("as VFP_arch", "SP only", "DP only", "SP and DP"); + return true; + case 28: + *tag_name = "ABI_VFP_args"; + KNOWN_VALUES ("AAPCS", "VFP registers", "custom"); + return true; + case 29: + *tag_name = "ABI_WMMX_args"; + KNOWN_VALUES ("AAPCS", "WMMX registers", "custom"); + return true; + case 30: + *tag_name = "ABI_optimization_goals"; + KNOWN_VALUES ("None", + "Prefer Speed", + "Aggressive Speed", + "Prefer Size", + "Aggressive Size", + "Prefer Debug", + "Aggressive Debug"); + return true; + case 31: + *tag_name = "ABI_FP_optimization_goals"; + KNOWN_VALUES ("None", + "Prefer Speed", + "Aggressive Speed", + "Prefer Size", + "Aggressive Size", + "Prefer Accuracy", + "Aggressive Accuracy"); + return true; + case 34: + *tag_name = "CPU_unaligned_access"; + KNOWN_VALUES ("None", "v6"); + return true; + case 36: + *tag_name = "VFP_HP_extension"; + KNOWN_VALUES ("Not Allowed", "Allowed"); + return true; + case 38: + *tag_name = "ABI_FP_16bit_format"; + KNOWN_VALUES ("None", "IEEE 754", "Alternative Format"); + return true; + case 64: + *tag_name = "nodefaults"; + return true; + case 65: + *tag_name = "also_compatible_with"; + return true; + case 66: + *tag_name = "T2EE_use"; + KNOWN_VALUES ("Not Allowed", "Allowed"); + return true; + case 67: + *tag_name = "conformance"; + return true; + case 68: + *tag_name = "Virtualization_use"; + KNOWN_VALUES ("Not Allowed", "Allowed"); + return true; + case 70: + *tag_name = "MPextension_use"; + KNOWN_VALUES ("Not Allowed", "Allowed"); + return true; + } + + return false; +} diff --git a/backends/arm_auxv.c b/backends/arm_auxv.c new file mode 100644 index 00000000..3282bafc --- /dev/null +++ b/backends/arm_auxv.c @@ -0,0 +1,49 @@ +/* ARM-specific auxv handling. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND arm_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "swp\0" "half\0" "thumb\0" "26bit\0" + "fast-mult\0" "fpa\0" "vfp\0" "edsp\0" + "java\0" "iwmmxt\0" + "\0"; + return 1; +} diff --git a/backends/arm_cfi.c b/backends/arm_cfi.c new file mode 100644 index 00000000..971a1fc4 --- /dev/null +++ b/backends/arm_cfi.c @@ -0,0 +1,90 @@ +/* arm ABI-specified defaults for DWARF CFI. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + + +/* ABI-specified state of DWARF CFI based on: + + "DWARF for the ARM Architecture ABI r2.09" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf + + "Procedure Call Standard for the ARM Architecture ABI r2.09" +http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf +*/ + +int +arm_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* The initial Canonical Frame Address is the value of the + Stack Pointer (r13) as setup in the previous frame. */ + DW_CFA_def_cfa, ULEB128_7 (13), ULEB128_7 (0), + + /* The Stack Pointer (r13) is restored from CFA address by default. */ + DW_CFA_val_offset, ULEB128_7 (13), ULEB128_7 (0), + +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + /* Callee-saved regs r4-r8, r10, r11. */ + SV (4), SV (5), SV (6), SV (7), SV (8), SV (10), SV (11), + + /* The link register contains the return address setup by caller. */ + SV (14), + DW_CFA_register, ULEB128_7 (15), ULEB128_7 (14), /* pc = lr */ +#undef SV + + /* VFP S16-S31/D8-D15/Q4-Q7 are callee saved. + And uleb128 encoded with two bytes. */ +#define ULEB128_8_2(x) ((x & 0x7f) | 0x80), 0x02 +#define SV(n) DW_CFA_same_value, ULEB128_8_2 (n) + SV (264), SV (265), SV (266), SV (267), + SV (268), SV (269), SV (270), SV (271), + + /* XXX Note: registers intentionally unused by the program, + for example as a consequence of the procedure call standard + should be initialized as if by DW_CFA_same_value. */ + }; +#undef ULEB128_8_2 +#undef SV + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = 4; + + abi_info->return_address_register = 15; /* pc. */ + + return 0; +} diff --git a/backends/arm_corenote.c b/backends/arm_corenote.c new file mode 100644 index 00000000..c5d8d887 --- /dev/null +++ b/backends/arm_corenote.c @@ -0,0 +1,94 @@ +/* ARM specific core note handling. + Copyright (C) 2009, 2012 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 16, .bits = 32 }, /* r0..r15 */ + { .offset = 16 * 4, .regno = 128, .count = 1, .bits = 32 }, /* cpsr */ + }; +#define PRSTATUS_REGS_SIZE (18 * 4) + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_r0", .type = ELF_T_SWORD, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (4 * 17), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 96, .count = 8, .bits = 96 }, /* f0..f7 */ + }; +#define FPREGSET_SIZE 116 + +#define ULONG uint32_t +#define PID_T int32_t +#define UID_T uint16_t +#define GID_T uint16_t +#define ALIGN_ULONG 4 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 2 +#define ALIGN_GID_T 2 +#define TYPE_ULONG ELF_T_WORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_HALF +#define TYPE_GID_T ELF_T_HALF + +#define ARM_VFPREGS_SIZE ( 32 * 8 /*fpregs*/ + 4 /*fpscr*/ ) +static const Ebl_Register_Location vfp_regs[] = + { + { .offset = 0, .regno = 256, .count = 32, .bits = 64 }, /* fpregs */ + }; + +static const Ebl_Core_Item vfp_items[] = + { + { + .name = "fpscr", .group = "register", + .offset = 0, + .type = ELF_T_WORD, .format = 'x', + }, + }; + +#define EXTRA_NOTES \ + EXTRA_REGSET_ITEMS (NT_ARM_VFP, ARM_VFPREGS_SIZE, vfp_regs, vfp_items) + +#include "linux-core-note.c" diff --git a/backends/arm_init.c b/backends/arm_init.c new file mode 100644 index 00000000..3283c978 --- /dev/null +++ b/backends/arm_init.c @@ -0,0 +1,76 @@ +/* Initialization of Arm specific backend library. + Copyright (C) 2002, 2005, 2009, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND arm_ +#define RELOC_PREFIX R_ARM_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on arm_reloc.def. */ +#include "common-reloc.c" + + +const char * +arm_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "ARM"; + arm_init_reloc (eh); + HOOK (eh, segment_type_name); + HOOK (eh, section_type_name); + HOOK (eh, machine_flag_check); + HOOK (eh, reloc_simple_type); + HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, auxv_info); + HOOK (eh, check_object_attribute); + HOOK (eh, return_value_location); + HOOK (eh, abi_cfi); + HOOK (eh, check_reloc_target_type); + + /* We only unwind the core integer registers. */ + eh->frame_nregs = 16; + HOOK (eh, set_initial_registers_tid); + + /* Bit zero encodes whether an function address is THUMB or ARM. */ + eh->func_addr_mask = ~(GElf_Addr)1; + + return MODVERSION; +} diff --git a/backends/arm_initreg.c b/backends/arm_initreg.c new file mode 100644 index 00000000..a0a9be94 --- /dev/null +++ b/backends/arm_initreg.c @@ -0,0 +1,92 @@ +/* Fetch live process registers from TID. + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined __arm__ +# include <sys/types.h> +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#ifdef __aarch64__ +# include <linux/uio.h> +# include <sys/user.h> +# include <sys/ptrace.h> +/* Deal with old glibc defining user_pt_regs instead of user_regs_struct. */ +# ifndef HAVE_SYS_USER_REGS +# define user_regs_struct user_pt_regs +# endif +#endif + +#define BACKEND arm_ +#include "libebl_CPU.h" + +bool +arm_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#if !defined __arm__ && !defined __aarch64__ + return false; +#else /* __arm__ || __aarch64__ */ +#if defined __arm__ + struct user_regs user_regs; + if (ptrace (PTRACE_GETREGS, tid, NULL, &user_regs) != 0) + return false; + + Dwarf_Word dwarf_regs[16]; + /* R0..R12 SP LR PC */ + for (int i = 0; i < 16; i++) + dwarf_regs[i] = user_regs.uregs[i]; + + return setfunc (0, 16, dwarf_regs, arg); +#elif defined __aarch64__ + /* Compat mode: arm compatible code running on aarch64 */ + int i; + struct user_regs_struct gregs; + struct iovec iovec; + iovec.iov_base = &gregs; + iovec.iov_len = sizeof (gregs); + if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec) != 0) + return false; + + Dwarf_Word dwarf_regs[16]; + /* R0..R12 SP LR PC, encoded as 32 bit quantities */ + uint32_t *u32_ptr = (uint32_t *) &gregs.regs[0]; + for (i = 0; i < 16; i++) + dwarf_regs[i] = u32_ptr[i]; + + return setfunc (0, 16, dwarf_regs, arg); +#else +# error "source file error, it cannot happen" +#endif +#endif +} diff --git a/backends/arm_regs.c b/backends/arm_regs.c new file mode 100644 index 00000000..21c5ad3a --- /dev/null +++ b/backends/arm_regs.c @@ -0,0 +1,120 @@ +/* Register names and numbers for ARM DWARF. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + +ssize_t +arm_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 320; + + if (regno < 0 || regno > 320 || namelen < 5) + return -1; + + *prefix = ""; + *bits = 32; + *type = DW_ATE_signed; + *setname = "integer"; + + switch (regno) + { + case 0 ... 9: + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 12: + name[0] = 'r'; + name[1] = '1'; + name[2] = regno % 10 + '0'; + namelen = 3; + break; + + case 13 ... 15: + *type = DW_ATE_address; + name[0] = "slp"[regno - 13]; + name[1] = "prc"[regno - 13]; + namelen = 2; + break; + + case 16 + 0 ... 16 + 7: + regno += 96 - 16; + /* Fall through. */ + case 96 + 0 ... 96 + 7: + *setname = "FPA"; + *type = DW_ATE_float; + *bits = 96; + name[0] = 'f'; + name[1] = regno - 96 + '0'; + namelen = 2; + break; + + case 128: + *type = DW_ATE_unsigned; + return stpcpy (name, "spsr") + 1 - name; + + case 256 + 0 ... 256 + 9: + *setname = "VFP"; + *type = DW_ATE_float; + *bits = 64; + name[0] = 'd'; + name[1] = regno - 256 + '0'; + namelen = 2; + break; + + case 256 + 10 ... 256 + 31: + *setname = "VFP"; + *type = DW_ATE_float; + *bits = 64; + name[0] = 'd'; + name[1] = (regno - 256) / 10 + '0'; + name[2] = (regno - 256) % 10 + '0'; + namelen = 3; + break; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/arm_reloc.def b/backends/arm_reloc.def new file mode 100644 index 00000000..4b7894bb --- /dev/null +++ b/backends/arm_reloc.def @@ -0,0 +1,157 @@ +/* List the relocation types for arm. -*- C -*- + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, REL) /* It really is used in ET_REL on ARM. */ +RELOC_TYPE (PC24, REL|EXEC|DYN) +RELOC_TYPE (ABS32, REL|EXEC|DYN) +RELOC_TYPE (REL32, REL) +RELOC_TYPE (PC13, REL) +RELOC_TYPE (ABS16, REL) +RELOC_TYPE (ABS12, REL) +RELOC_TYPE (THM_ABS5, REL) +RELOC_TYPE (ABS8, REL) +RELOC_TYPE (SBREL32, REL) +RELOC_TYPE (THM_PC22, REL) +RELOC_TYPE (THM_PC8, REL) +RELOC_TYPE (AMP_VCALL9, REL) +RELOC_TYPE (TLS_DESC, EXEC|DYN) +RELOC_TYPE (THM_SWI8, REL) +RELOC_TYPE (XPC25, REL) +RELOC_TYPE (THM_XPC22, REL) +RELOC_TYPE (TLS_DTPMOD32, EXEC|DYN) +RELOC_TYPE (TLS_DTPOFF32, EXEC|DYN) +RELOC_TYPE (TLS_TPOFF32, EXEC|DYN) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JUMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTOFF, REL) +RELOC_TYPE (GOTPC, REL) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (CALL, REL) +RELOC_TYPE (JUMP24, REL) +RELOC_TYPE (THM_JUMP24, REL) +RELOC_TYPE (BASE_ABS, REL) +RELOC_TYPE (ALU_PCREL_7_0, REL) +RELOC_TYPE (ALU_PCREL_15_8, REL) +RELOC_TYPE (ALU_PCREL_23_15, REL) +RELOC_TYPE (LDR_SBREL_11_0, REL) +RELOC_TYPE (ALU_SBREL_19_12, REL) +RELOC_TYPE (ALU_SBREL_27_20, REL) +RELOC_TYPE (TARGET1, REL) +RELOC_TYPE (SBREL31, REL) +RELOC_TYPE (V4BX, REL) +RELOC_TYPE (TARGET2, REL) +RELOC_TYPE (PREL31, REL) +RELOC_TYPE (MOVW_ABS_NC, REL) +RELOC_TYPE (MOVT_ABS, REL) +RELOC_TYPE (MOVW_PREL_NC, REL) +RELOC_TYPE (MOVT_PREL, REL) +RELOC_TYPE (THM_MOVW_ABS_NC, REL) +RELOC_TYPE (THM_MOVT_ABS, REL) +RELOC_TYPE (THM_MOVW_PREL_NC, REL) +RELOC_TYPE (THM_MOVT_PREL, REL) +RELOC_TYPE (THM_JUMP19, REL) +RELOC_TYPE (THM_JUMP6, REL) +RELOC_TYPE (THM_ALU_PREL_11_0, REL) +RELOC_TYPE (THM_PC12, REL) +RELOC_TYPE (ABS32_NOI, REL) +RELOC_TYPE (REL32_NOI, REL) +RELOC_TYPE (ALU_PC_G0_NC, REL) +RELOC_TYPE (ALU_PC_G0, REL) +RELOC_TYPE (ALU_PC_G1_NC, REL) +RELOC_TYPE (ALU_PC_G1, REL) +RELOC_TYPE (ALU_PC_G2, REL) +RELOC_TYPE (LDR_PC_G1, REL) +RELOC_TYPE (LDR_PC_G2, REL) +RELOC_TYPE (LDRS_PC_G0, REL) +RELOC_TYPE (LDRS_PC_G1, REL) +RELOC_TYPE (LDRS_PC_G2, REL) +RELOC_TYPE (LDC_PC_G0, REL) +RELOC_TYPE (LDC_PC_G1, REL) +RELOC_TYPE (LDC_PC_G2, REL) +RELOC_TYPE (ALU_SB_G0_NC, REL) +RELOC_TYPE (ALU_SB_G0, REL) +RELOC_TYPE (ALU_SB_G1_NC, REL) +RELOC_TYPE (ALU_SB_G1, REL) +RELOC_TYPE (ALU_SB_G2, REL) +RELOC_TYPE (LDR_SB_G0, REL) +RELOC_TYPE (LDR_SB_G1, REL) +RELOC_TYPE (LDR_SB_G2, REL) +RELOC_TYPE (LDRS_SB_G0, REL) +RELOC_TYPE (LDRS_SB_G1, REL) +RELOC_TYPE (LDRS_SB_G2, REL) +RELOC_TYPE (LDC_SB_G0, REL) +RELOC_TYPE (LDC_SB_G1, REL) +RELOC_TYPE (LDC_SB_G2, REL) +RELOC_TYPE (MOVW_BREL_NC, REL) +RELOC_TYPE (MOVT_BREL, REL) +RELOC_TYPE (MOVW_BREL, REL) +RELOC_TYPE (THM_MOVW_BREL_NC, REL) +RELOC_TYPE (THM_MOVT_BREL, REL) +RELOC_TYPE (THM_MOVW_BREL, REL) +RELOC_TYPE (TLS_GOTDESC, REL) +RELOC_TYPE (TLS_CALL, REL) +RELOC_TYPE (TLS_DESCSEQ, REL) +RELOC_TYPE (THM_TLS_CALL, REL) +RELOC_TYPE (PLT32_ABS, REL) +RELOC_TYPE (GOT_ABS, REL) +RELOC_TYPE (GOT_PREL, REL) +RELOC_TYPE (GOT_BREL12, REL) +RELOC_TYPE (GOTOFF12, REL) +RELOC_TYPE (GOTRELAX, REL) +RELOC_TYPE (GNU_VTENTRY, REL) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (THM_PC11, REL) +RELOC_TYPE (THM_PC9, REL) +RELOC_TYPE (TLS_GD32, REL) +RELOC_TYPE (TLS_LDM32, REL) +RELOC_TYPE (TLS_LDO32, REL) +RELOC_TYPE (TLS_IE32, REL) +RELOC_TYPE (TLS_LE32, REL) +RELOC_TYPE (TLS_LDO12, REL) +RELOC_TYPE (TLS_LE12, REL) +RELOC_TYPE (TLS_IE12GP, REL) + +RELOC_TYPE (ME_TOO, REL) +RELOC_TYPE (THM_TLS_DESCSEQ16, REL) +RELOC_TYPE (THM_TLS_DESCSEQ32, REL) +RELOC_TYPE (THM_GOT_BREL12, REL) + +RELOC_TYPE (IRELATIVE, EXEC|DYN) + +RELOC_TYPE (RXPC25, REL) +RELOC_TYPE (RSBREL32, REL) +RELOC_TYPE (THM_RPC22, REL) +RELOC_TYPE (RREL32, REL) +RELOC_TYPE (RABS22, REL) +RELOC_TYPE (RPC24, REL) +RELOC_TYPE (RBASE, REL) diff --git a/backends/arm_retval.c b/backends/arm_retval.c new file mode 100644 index 00000000..7aced742 --- /dev/null +++ b/backends/arm_retval.c @@ -0,0 +1,127 @@ +/* Function return value location for ARM EABI. + Copyright (C) 2009-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + + +/* r0, or pair r0, r1, or aggregate up to r0-r3. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregs(n) (2 * (n)) + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + + +int +arm_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + if (size <= 16) + { + intreg: + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregs ((size + 3) / 4); + } + + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + } + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_aggregate_size (typedie, &size) == 0 + && size > 0 && size <= 4) + goto intreg; + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/arm_symbol.c b/backends/arm_symbol.c new file mode 100644 index 00000000..cd467ffc --- /dev/null +++ b/backends/arm_symbol.c @@ -0,0 +1,131 @@ +/* Arm specific symbolic name handling. + Copyright (C) 2002-2009, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND arm_ +#include "libebl_CPU.h" + + +const char * +arm_segment_type_name (int segment, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (segment) + { + case PT_ARM_EXIDX: + return "ARM_EXIDX"; + } + return NULL; +} + +/* Return symbolic representation of section type. */ +const char * +arm_section_type_name (int type, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (type) + { + case SHT_ARM_EXIDX: + return "ARM_EXIDX"; + case SHT_ARM_PREEMPTMAP: + return "ARM_PREEMPTMAP"; + case SHT_ARM_ATTRIBUTES: + return "ARM_ATTRIBUTES"; + } + + return NULL; +} + +/* Check whether machine flags are valid. */ +bool +arm_machine_flag_check (GElf_Word flags) +{ + switch (flags & EF_ARM_EABIMASK) + { + case EF_ARM_EABI_UNKNOWN: + case EF_ARM_EABI_VER1: + case EF_ARM_EABI_VER2: + case EF_ARM_EABI_VER3: + case EF_ARM_EABI_VER4: + case EF_ARM_EABI_VER5: + break; + default: + return false; + } + + return ((flags &~ (EF_ARM_EABIMASK + | EF_ARM_RELEXEC + | EF_ARM_HASENTRY + | EF_ARM_INTERWORK + | EF_ARM_APCS_26 + | EF_ARM_APCS_FLOAT + | EF_ARM_PIC + | EF_ARM_ALIGN8 + | EF_ARM_NEW_ABI + | EF_ARM_OLD_ABI + | EF_ARM_SOFT_FLOAT + | EF_ARM_VFP_FLOAT + | EF_ARM_MAVERICK_FLOAT + | EF_ARM_SYMSARESORTED + | EF_ARM_DYNSYMSUSESEGIDX + | EF_ARM_MAPSYMSFIRST + | EF_ARM_EABIMASK + | EF_ARM_BE8 + | EF_ARM_LE8)) == 0); +} + +/* Check for the simple reloc types. */ +Elf_Type +arm_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_ARM_ABS32: + return ELF_T_WORD; + case R_ARM_ABS16: + return ELF_T_HALF; + case R_ARM_ABS8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} + +/* The SHT_ARM_EXIDX section type is a valid target for relocation. */ +bool +arm_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type) +{ + return sh_type == SHT_ARM_EXIDX; +} diff --git a/backends/common-reloc.c b/backends/common-reloc.c new file mode 100644 index 00000000..2667ec4a --- /dev/null +++ b/backends/common-reloc.c @@ -0,0 +1,146 @@ +/* Common code for ebl reloc functions. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include "libebl_CPU.h" +#include <assert.h> + +#define R_TYPE(name) PASTE (RELOC_PREFIX, name) +#define PASTE(a, b) PASTE_1 (a, b) +#define PASTE_1(a, b) a##b +#define R_NAME(name) R_NAME_1 (RELOC_PREFIX, name) +#define R_NAME_1(prefix, type) R_NAME_2 (prefix, type) +#define R_NAME_2(prefix, type) #prefix #type + +#define RELOC_TYPES STRINGIFIED_PASTE (BACKEND, reloc.def) +#define STRINGIFIED_PASTE(a, b) STRINGIFY (PASTE (a, b)) +#define STRINGIFY(x) STRINGIFY_1 (x) +#define STRINGIFY_1(x) #x + +/* Provide a table of reloc type names, in a PIC-friendly fashion. */ + +static const struct EBLHOOK(reloc_nametable) +{ + char zero; +#define RELOC_TYPE(type, uses) \ + char name_##type[sizeof R_NAME (type)]; +#include RELOC_TYPES +#undef RELOC_TYPE +} EBLHOOK(reloc_nametable) = + { + '\0', +#define RELOC_TYPE(type, uses) R_NAME (type), +#include RELOC_TYPES +#undef RELOC_TYPE + }; +#define reloc_namestr (&EBLHOOK(reloc_nametable).zero) + +static const uint_fast16_t EBLHOOK(reloc_nameidx)[] = +{ +#define RELOC_TYPE(type, uses) \ + [R_TYPE (type)] = offsetof (struct EBLHOOK(reloc_nametable), name_##type), +#include RELOC_TYPES +#undef RELOC_TYPE +}; +#define nreloc \ + ((int) (sizeof EBLHOOK(reloc_nameidx) / sizeof EBLHOOK(reloc_nameidx)[0])) + +#define REL (1 << (ET_REL - 1)) +#define EXEC (1 << (ET_EXEC - 1)) +#define DYN (1 << (ET_DYN - 1)) +static const uint8_t EBLHOOK(reloc_valid)[] = +{ +#define RELOC_TYPE(type, uses) [R_TYPE (type)] = uses, +#include RELOC_TYPES +#undef RELOC_TYPE +}; +#undef REL +#undef EXEC +#undef DYN + +const char * +EBLHOOK(reloc_type_name) (int reloc, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + if (reloc >= 0 && reloc < nreloc && EBLHOOK(reloc_nameidx)[reloc] != 0) + return &reloc_namestr[EBLHOOK(reloc_nameidx)[reloc]]; + return NULL; +} + +bool +EBLHOOK(reloc_type_check) (int reloc) +{ + return reloc >= 0 && reloc < nreloc && EBLHOOK(reloc_nameidx)[reloc] != 0; +} + +bool +EBLHOOK(reloc_valid_use) (Elf *elf, int reloc) +{ + uint8_t uses = EBLHOOK(reloc_valid)[reloc]; + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); + assert (ehdr != NULL); + uint8_t type = ehdr->e_type; + + return type > ET_NONE && type < ET_CORE && (uses & (1 << (type - 1))); +} + + +bool +EBLHOOK(copy_reloc_p) (int reloc) +{ + return reloc == R_TYPE (COPY); +} + +bool +EBLHOOK(none_reloc_p) (int reloc) +{ + return reloc == R_TYPE (NONE); +} + +#ifndef NO_RELATIVE_RELOC +bool +EBLHOOK(relative_reloc_p) (int reloc) +{ + return reloc == R_TYPE (RELATIVE); +} +#endif + +static void +EBLHOOK(init_reloc) (Ebl *ebl) +{ + ebl->reloc_type_name = EBLHOOK(reloc_type_name); + ebl->reloc_type_check = EBLHOOK(reloc_type_check); + ebl->reloc_valid_use = EBLHOOK(reloc_valid_use); + ebl->copy_reloc_p = EBLHOOK(copy_reloc_p); + ebl->none_reloc_p = EBLHOOK(none_reloc_p); +#ifndef NO_RELATIVE_RELOC + ebl->relative_reloc_p = EBLHOOK(relative_reloc_p); +#endif +} diff --git a/backends/i386_auxv.c b/backends/i386_auxv.c new file mode 100644 index 00000000..dba63fe0 --- /dev/null +++ b/backends/i386_auxv.c @@ -0,0 +1,52 @@ +/* i386 specific auxv handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND i386_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "fpu\0" "vme\0" "de\0" "pse\0" "tsc\0" "msr\0" "pae\0" "mce\0" + "cx8\0" "apic\0" "10\0" "sep\0" "mtrr\0" "pge\0" "mca\0" "cmov\0" + "pat\0" "pse36\0" "pn\0" "clflush\0" "20\0" "dts\0" "acpi\0" "mmx\0" + "fxsr\0" "sse\0" "sse2\0" "ss\0" "ht\0" "tm\0" "ia64\0" "pbe\0" "\0"; + return 1; +} + +__typeof (i386_auxv_info) x86_64_auxv_info + __attribute__ ((alias ("i386_auxv_info"))); diff --git a/backends/i386_cfi.c b/backends/i386_cfi.c new file mode 100644 index 00000000..31f85f7e --- /dev/null +++ b/backends/i386_cfi.c @@ -0,0 +1,68 @@ +/* i386 ABI-specified defaults for DWARF CFI. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + +int +i386_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* Call-saved regs. */ + DW_CFA_same_value, ULEB128_7 (3), /* %ebx */ + DW_CFA_same_value, ULEB128_7 (5), /* %ebp */ + DW_CFA_same_value, ULEB128_7 (6), /* %esi */ + DW_CFA_same_value, ULEB128_7 (7), /* %edi */ + + /* The CFA is the SP. */ + DW_CFA_val_offset, ULEB128_7 (4), ULEB128_7 (0), + + /* Segment registers are call-saved if ever used at all. */ + DW_CFA_same_value, ULEB128_7 (40), /* %es */ + DW_CFA_same_value, ULEB128_7 (41), /* %cs */ + DW_CFA_same_value, ULEB128_7 (42), /* %ss */ + DW_CFA_same_value, ULEB128_7 (43), /* %ds */ + DW_CFA_same_value, ULEB128_7 (44), /* %fs */ + DW_CFA_same_value, ULEB128_7 (45), /* %gs */ + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = 4; + + abi_info->return_address_register = 8; /* %eip */ + + return 0; +} diff --git a/backends/i386_corenote.c b/backends/i386_corenote.c new file mode 100644 index 00000000..15cd66b5 --- /dev/null +++ b/backends/i386_corenote.c @@ -0,0 +1,138 @@ +/* i386 specific core note handling. + Copyright (C) 2007-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * 4, .regno = dwreg, .count = n, .bits = 32 } +#define SR(at, n, dwreg) \ + { .offset = at * 4, .regno = dwreg, .count = n, .bits = 16, .pad = 2 } + + GR (0, 1, 3), /* %ebx */ + GR (1, 2, 1), /* %ecx-%edx */ + GR (3, 2, 6), /* %esi-%edi */ + GR (5, 1, 5), /* %ebp */ + GR (6, 1, 0), /* %eax */ + SR (7, 1, 43), /* %ds */ + SR (8, 1, 40), /* %es */ + SR (9, 1, 44), /* %fs */ + SR (10, 1, 45), /* %gs */ + /* 11, 1, orig_eax */ + GR (12, 1, 8), /* %eip */ + SR (13, 1, 41), /* %cs */ + GR (14, 1, 9), /* eflags */ + GR (15, 1, 4), /* %esp */ + SR (16, 1, 42), /* %ss */ + +#undef GR +#undef SR + }; +#define PRSTATUS_REGS_SIZE (17 * 4) + +#define ULONG uint32_t +#define PID_T int32_t +#define UID_T uint16_t +#define GID_T uint16_t +#define ALIGN_ULONG 4 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 2 +#define ALIGN_GID_T 2 +#define TYPE_ULONG ELF_T_WORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_HALF +#define TYPE_GID_T ELF_T_HALF + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_eax", .type = ELF_T_SWORD, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (4 * 11), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 37, .count = 2, .bits = 32 }, /* fctrl-fstat */ + { .offset = 7 * 4, .regno = 11, .count = 8, .bits = 80 }, /* stN */ + }; +#define FPREGSET_SIZE 108 + +static const Ebl_Register_Location prxfpreg_regs[] = + { + { .offset = 0, .regno = 37, .count = 2, .bits = 16 }, /* fctrl-fstat */ + { .offset = 24, .regno = 39, .count = 1, .bits = 32 }, /* mxcsr */ + { .offset = 32, .regno = 11, .count = 8, .bits = 80, .pad = 6 }, /* stN */ + { .offset = 32 + 128, .regno = 21, .count = 8, .bits = 128 }, /* xmm */ + }; + +#define EXTRA_NOTES \ + EXTRA_REGSET (NT_PRXFPREG, 512, prxfpreg_regs) \ + case NT_386_TLS: \ + return tls_info (nhdr->n_descsz, regs_offset, nregloc, reglocs, \ + nitems, items); \ + EXTRA_NOTES_IOPERM + +static const Ebl_Core_Item tls_items[] = + { + { .type = ELF_T_WORD, .offset = 0x0, .format = 'd', .name = "index" }, + { .type = ELF_T_WORD, .offset = 0x4, .format = 'x', .name = "base" }, + { .type = ELF_T_WORD, .offset = 0x8, .format = 'x', .name = "limit" }, + { .type = ELF_T_WORD, .offset = 0xc, .format = 'x', .name = "flags" }, + }; + +static int +tls_info (GElf_Word descsz, GElf_Word *regs_offset, + size_t *nregloc, const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **items) +{ + if (descsz % 16 != 0) + return 0; + + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + *nitems = sizeof tls_items / sizeof tls_items[0]; + *items = tls_items; + return 1; +} + +#include "x86_corenote.c" +#include "linux-core-note.c" diff --git a/backends/i386_init.c b/backends/i386_init.c new file mode 100644 index 00000000..1e0b4863 --- /dev/null +++ b/backends/i386_init.c @@ -0,0 +1,71 @@ +/* Initialization of i386 specific backend library. + Copyright (C) 2000-2009, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND i386_ +#define RELOC_PREFIX R_386_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on i386_reloc.def. */ +#include "common-reloc.c" + +const char * +i386_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Intel 80386"; + i386_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, gotpc_reloc_check); + HOOK (eh, core_note); + generic_debugscn_p = eh->debugscn_p; + HOOK (eh, debugscn_p); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, syscall_abi); + HOOK (eh, auxv_info); + HOOK (eh, disasm); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. For i386 it is 17, why? */ + eh->frame_nregs = 9; + HOOK (eh, set_initial_registers_tid); + + return MODVERSION; +} diff --git a/backends/i386_initreg.c b/backends/i386_initreg.c new file mode 100644 index 00000000..51fd9ea6 --- /dev/null +++ b/backends/i386_initreg.c @@ -0,0 +1,79 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if defined __i386__ || defined __x86_64__ +# include <sys/types.h> +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND i386_ +#include "libebl_CPU.h" + +bool +i386_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#if (!defined __i386__ && !defined __x86_64__) || !defined(__linux__) + return false; +#else /* __i386__ || __x86_64__ */ + struct user_regs_struct user_regs; + if (ptrace (PTRACE_GETREGS, tid, NULL, &user_regs) != 0) + return false; + Dwarf_Word dwarf_regs[9]; +# if defined __i386__ + dwarf_regs[0] = user_regs.eax; + dwarf_regs[1] = user_regs.ecx; + dwarf_regs[2] = user_regs.edx; + dwarf_regs[3] = user_regs.ebx; + dwarf_regs[4] = user_regs.esp; + dwarf_regs[5] = user_regs.ebp; + dwarf_regs[6] = user_regs.esi; + dwarf_regs[7] = user_regs.edi; + dwarf_regs[8] = user_regs.eip; +# elif defined __x86_64__ + dwarf_regs[0] = user_regs.rax; + dwarf_regs[1] = user_regs.rcx; + dwarf_regs[2] = user_regs.rdx; + dwarf_regs[3] = user_regs.rbx; + dwarf_regs[4] = user_regs.rsp; + dwarf_regs[5] = user_regs.rbp; + dwarf_regs[6] = user_regs.rsi; + dwarf_regs[7] = user_regs.rdi; + dwarf_regs[8] = user_regs.rip; +# else /* (__i386__ || __x86_64__) && (!__i386__ && !__x86_64__) */ +# error "source file error, it cannot happen" +# endif /* (__i386__ || __x86_64__) && (!__i386__ && !__x86_64__) */ + return setfunc (0, 9, dwarf_regs, arg); +#endif /* __i386__ || __x86_64__ */ +} diff --git a/backends/i386_regs.c b/backends/i386_regs.c new file mode 100644 index 00000000..fb8ded33 --- /dev/null +++ b/backends/i386_regs.c @@ -0,0 +1,152 @@ +/* Register names and numbers for i386 DWARF. + Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + +ssize_t +i386_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 46; + + if (regno < 0 || regno > 45 || namelen < 6) + return -1; + + *prefix = "%"; + *bits = 32; + *type = DW_ATE_unsigned; + if (regno < 11) + { + *setname = "integer"; + if (regno < 9) + *type = DW_ATE_signed; + } + else if (regno < 19) + { + *setname = "x87"; + *type = DW_ATE_float; + *bits = 80; + } + else if (regno < 29) + { + *setname = "SSE"; + *bits = 128; + } + else if (regno < 37) + { + *setname = "MMX"; + *bits = 64; + } + else if (regno < 40) + *setname = "FPU-control"; + else + { + *setname = "segment"; + *bits = 16; + } + + switch (regno) + { + static const char baseregs[][2] = + { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "ip" + }; + + case 4: + case 5: + case 8: + *type = DW_ATE_address; + case 0 ... 3: + case 6 ... 7: + name[0] = 'e'; + name[1] = baseregs[regno][0]; + name[2] = baseregs[regno][1]; + namelen = 3; + break; + + case 9: + return stpcpy (name, "eflags") + 1 - name; + case 10: + return stpcpy (name, "trapno") + 1 - name; + + case 11 ... 18: + name[0] = 's'; + name[1] = 't'; + name[2] = regno - 11 + '0'; + namelen = 3; + break; + + case 21 ... 28: + name[0] = 'x'; + name[1] = 'm'; + name[2] = 'm'; + name[3] = regno - 21 + '0'; + namelen = 4; + break; + + case 29 ... 36: + name[0] = 'm'; + name[1] = 'm'; + name[2] = regno - 29 + '0'; + namelen = 3; + break; + + case 37: + *bits = 16; + return stpcpy (name, "fctrl") + 1 - name; + case 38: + *bits = 16; + return stpcpy (name, "fstat") + 1 - name; + case 39: + return stpcpy (name, "mxcsr") + 1 - name; + + case 40 ... 45: + name[0] = "ecsdfg"[regno - 40]; + name[1] = 's'; + namelen = 2; + break; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/i386_reloc.def b/backends/i386_reloc.def new file mode 100644 index 00000000..bd273b38 --- /dev/null +++ b/backends/i386_reloc.def @@ -0,0 +1,70 @@ +/* List the relocation types for i386. -*- C -*- + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (32, REL|EXEC|DYN) +RELOC_TYPE (PC32, REL|EXEC|DYN) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTOFF, REL) +RELOC_TYPE (GOTPC, REL) +RELOC_TYPE (32PLT, REL) +RELOC_TYPE (TLS_TPOFF, EXEC|DYN) +RELOC_TYPE (TLS_IE, REL) +RELOC_TYPE (TLS_GOTIE, REL) +RELOC_TYPE (TLS_LE, REL) +RELOC_TYPE (TLS_GD, REL) +RELOC_TYPE (TLS_LDM, REL) +RELOC_TYPE (16, REL) +RELOC_TYPE (PC16, REL) +RELOC_TYPE (8, REL) +RELOC_TYPE (PC8, REL) +RELOC_TYPE (TLS_GD_32, REL) +RELOC_TYPE (TLS_GD_PUSH, REL) +RELOC_TYPE (TLS_GD_CALL, REL) +RELOC_TYPE (TLS_GD_POP, REL) +RELOC_TYPE (TLS_LDM_32, REL) +RELOC_TYPE (TLS_LDM_PUSH, REL) +RELOC_TYPE (TLS_LDM_CALL, REL) +RELOC_TYPE (TLS_LDM_POP, REL) +RELOC_TYPE (TLS_LDO_32, REL) +RELOC_TYPE (TLS_IE_32, REL) +RELOC_TYPE (TLS_LE_32, REL) +RELOC_TYPE (TLS_DTPMOD32, EXEC|DYN) +RELOC_TYPE (TLS_DTPOFF32, EXEC|DYN) +RELOC_TYPE (TLS_TPOFF32, EXEC|DYN) +RELOC_TYPE (TLS_GOTDESC, REL) +RELOC_TYPE (TLS_DESC_CALL, REL) +RELOC_TYPE (TLS_DESC, EXEC) +RELOC_TYPE (IRELATIVE, EXEC|DYN) diff --git a/backends/i386_retval.c b/backends/i386_retval.c new file mode 100644 index 00000000..9da797d5 --- /dev/null +++ b/backends/i386_retval.c @@ -0,0 +1,141 @@ +/* Function return value location for Linux/i386 ABI. + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + + +/* %eax, or pair %eax, %edx. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %st(0). */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_reg11 } + }; +#define nloc_fpreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %eax. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + +int +i386_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Word size; + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + if (size > 16) + return -2; + *locp = loc_fpreg; + return nloc_fpreg; + } + } + *locp = loc_intreg; + if (size <= 4) + return nloc_intreg; + if (size <= 8) + return nloc_intregpair; + + /* Else fall through. */ + } + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + *locp = loc_aggregate; + return nloc_aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/i386_symbol.c b/backends/i386_symbol.c new file mode 100644 index 00000000..7dbf899f --- /dev/null +++ b/backends/i386_symbol.c @@ -0,0 +1,75 @@ +/* i386 specific symbolic name handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + + +/* Return true if the symbol type is that referencing the GOT. */ +bool +i386_gotpc_reloc_check (Elf *elf __attribute__ ((unused)), int type) +{ + return type == R_386_GOTPC; +} + +/* Check for the simple reloc types. */ +Elf_Type +i386_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_386_32: + return ELF_T_SWORD; + case R_386_16: + return ELF_T_HALF; + case R_386_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} + +/* Check section name for being that of a debug information section. */ +bool (*generic_debugscn_p) (const char *); +bool +i386_debugscn_p (const char *name) +{ + return (generic_debugscn_p (name) + || strcmp (name, ".stab") == 0 + || strcmp (name, ".stabstr") == 0); +} diff --git a/backends/i386_syscall.c b/backends/i386_syscall.c new file mode 100644 index 00000000..535dcd86 --- /dev/null +++ b/backends/i386_syscall.c @@ -0,0 +1,50 @@ +/* Linux/i386 system call ABI in DWARF register numbers. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND i386_ +#include "libebl_CPU.h" + +int +i386_syscall_abi (Ebl *ebl __attribute__ ((unused)), + int *sp, int *pc, int *callno, int args[6]) +{ + *sp = 4; /* %esp */ + *pc = 8; /* %eip */ + *callno = 0; /* %eax */ + args[0] = 3; /* %ebx */ + args[1] = 1; /* %ecx */ + args[2] = 2; /* %edx */ + args[3] = 6; /* %esi */ + args[4] = 7; /* %edi */ + args[5] = 5; /* %ebp */ + return 0; +} diff --git a/backends/ia64_init.c b/backends/ia64_init.c new file mode 100644 index 00000000..91da748d --- /dev/null +++ b/backends/ia64_init.c @@ -0,0 +1,67 @@ +/* Initialization of IA-64 specific backend library. + Copyright (C) 2002, 2003, 2005, 2006, 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ia64_ +#define RELOC_PREFIX R_IA64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on ia64_reloc.def. */ +#include "common-reloc.c" + +const char * +ia64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Intel IA-64"; + ia64_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, segment_type_name); + HOOK (eh, section_type_name); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, machine_flag_check); + HOOK (eh, machine_section_flag_check); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + HOOK (eh, check_reloc_target_type); + + return MODVERSION; +} diff --git a/backends/ia64_regs.c b/backends/ia64_regs.c new file mode 100644 index 00000000..a27fe63d --- /dev/null +++ b/backends/ia64_regs.c @@ -0,0 +1,273 @@ +/* Register names and numbers for IA64 DWARF. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND i386_ +#include "libebl_CPU.h" + +ssize_t +ia64_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 687 + 64; + + if (regno < 0 || regno > 687 + 63 || namelen < 12) + return -1; + + *prefix = "ar."; + *setname = "application"; + *bits = 64; + *type = DW_ATE_signed; + switch (regno) + { + case 0 ... 9: + name[0] = 'r'; + name[1] = (regno - 0) + '0'; + namelen = 2; + *setname = "integer"; + *prefix = ""; + break; + + case 10 ... 99: + name[0] = 'r'; + name[1] = (regno - 0) / 10 + '0'; + name[2] = (regno - 0) % 10 + '0'; + namelen = 3; + *setname = "integer"; + *prefix = ""; + break; + + case 100 ... 127: + name[0] = 'r'; + name[1] = '1'; + name[2] = (regno - 100) / 10 + '0'; + name[3] = (regno - 0) % 10 + '0'; + namelen = 4; + *setname = "integer"; + *prefix = ""; + break; + + case 128 + 0 ... 128 + 9: + name[0] = 'f'; + name[1] = (regno - 128) + '0'; + namelen = 2; + *type = DW_ATE_float; + *bits = 128; + *setname = "FPU"; + *prefix = ""; + break; + + case 128 + 10 ... 128 + 99: + name[0] = 'f'; + name[1] = (regno - 128) / 10 + '0'; + name[2] = (regno - 128) % 10 + '0'; + namelen = 3; + *setname = "FPU"; + *prefix = ""; + break; + + case 128 + 100 ... 128 + 127: + name[0] = 'f'; + name[1] = '1'; + name[2] = (regno - 128 - 100) / 10 + '0'; + name[3] = (regno - 128) % 10 + '0'; + namelen = 4; + *type = DW_ATE_float; + *bits = 128; + *setname = "FPU"; + *prefix = ""; + break; + + case 320 + 0 ... 320 + 7: + name[0] = 'b'; + name[1] = (regno - 320) + '0'; + namelen = 2; + *type = DW_ATE_address; + *setname = "branch"; + *prefix = ""; + break; + + case 328 ... 333: + { + static const char named_special[][5] = + { + "vfp", "vrap", "pr", "ip", "psr", "cfm" + }; + *setname = "special"; + *prefix = ""; + *type = regno == 331 ? DW_ATE_address : DW_ATE_unsigned; + return stpcpy (name, named_special[regno - 328]) + 1 - name; + } + + case 590: + *setname = "special"; + *prefix = ""; + *type = DW_ATE_unsigned; + return stpcpy (name, "bof") + 1 - name; + + case 334 + 0 ... 334 + 7: + name[0] = 'k'; + name[1] = 'r'; + name[2] = (regno - 334) + '0'; + namelen = 3; + *prefix = ""; + break; + + case 334 + 8 ... 334 + 127: + { + static const char named_ar[][9] = + { + [16 - 8] = "rsc", + [17 - 8] = "bsp", + [18 - 8] = "bspstore", + [19 - 8] = "rnat", + [21 - 8] = "fcr", + [24 - 8] = "eflag", + [25 - 8] = "csd", + [26 - 8] = "ssd", + [27 - 8] = "cflg", + [28 - 8] = "fsr", + [29 - 8] = "fir", + [30 - 8] = "fdr", + [32 - 8] = "ccv", + [36 - 8] = "unat", + [40 - 8] = "fpsr", + [44 - 8] = "itc", + [64 - 8] = "pfs", + [65 - 8] = "lc", + [66 - 8] = "ec", + }; + const size_t idx = regno - (334 + 8); + *type = DW_ATE_unsigned; + if (idx == 1 || idx == 2) + *type = DW_ATE_address; + if (idx < sizeof named_ar / sizeof named_ar[0] + && named_ar[idx][0] != '\0') + return stpcpy (name, named_ar[idx]) + 1 - name; + + name[0] = 'a'; + name[1] = 'r'; + switch (regno - 334) + { + case 0 ... 9: + name[2] = (regno - 334) + '0'; + namelen = 3; + break; + case 10 ... 99: + name[2] = (regno - 334) / 10 + '0'; + name[3] = (regno - 334) % 10 + '0'; + namelen = 4; + break; + case 100 ... 127: + name[2] = '1'; + name[3] = (regno - 334 - 100) / 10 + '0'; + name[4] = (regno - 334) % 10 + '0'; + namelen = 5; + break; + } + *prefix = ""; + break; + } + + case 462 + 0 ... 462 + 9: + name[0] = 'n'; + name[1] = 'a'; + name[2] = 't'; + name[3] = (regno - 462) + '0'; + namelen = 4; + *setname = "NAT"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + case 462 + 10 ... 462 + 99: + name[0] = 'n'; + name[1] = 'a'; + name[2] = 't'; + name[3] = (regno - 462) / 10 + '0'; + name[4] = (regno - 462) % 10 + '0'; + namelen = 5; + *setname = "NAT"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + case 462 + 100 ... 462 + 127: + name[0] = 'n'; + name[1] = 'a'; + name[2] = 't'; + name[3] = '1'; + name[4] = (regno - 462 - 100) / 10 + '0'; + name[5] = (regno - 462) % 10 + '0'; + namelen = 6; + *setname = "NAT"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + case 687 + 0 ... 687 + 9: + name[0] = 'p'; + name[1] = (regno - 687) + '0'; + namelen = 2; + *setname = "predicate"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + case 687 + 10 ... 687 + 63: + name[0] = 'p'; + name[1] = (regno - 687) / 10 + '0'; + name[2] = (regno - 687) % 10 + '0'; + namelen = 3; + *setname = "predicate"; + *type = DW_ATE_boolean; + *bits = 1; + *prefix = ""; + break; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/ia64_reloc.def b/backends/ia64_reloc.def new file mode 100644 index 00000000..9e058c8b --- /dev/null +++ b/backends/ia64_reloc.def @@ -0,0 +1,113 @@ +/* List the relocation types for ia64. -*- C -*- + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (IMM14, REL) +RELOC_TYPE (IMM22, REL) +RELOC_TYPE (IMM64, REL) +RELOC_TYPE (DIR32MSB, REL|EXEC|DYN) +RELOC_TYPE (DIR32LSB, REL|EXEC|DYN) +RELOC_TYPE (DIR64MSB, REL|EXEC|DYN) +RELOC_TYPE (DIR64LSB, REL|EXEC|DYN) +RELOC_TYPE (GPREL22, REL) +RELOC_TYPE (GPREL64I, REL) +RELOC_TYPE (GPREL32MSB, REL) +RELOC_TYPE (GPREL32LSB, REL) +RELOC_TYPE (GPREL64MSB, REL) +RELOC_TYPE (GPREL64LSB, REL) +RELOC_TYPE (LTOFF22, REL) +RELOC_TYPE (LTOFF64I, REL) +RELOC_TYPE (PLTOFF22, REL) +RELOC_TYPE (PLTOFF64I, REL) +RELOC_TYPE (PLTOFF64MSB, REL) +RELOC_TYPE (PLTOFF64LSB, REL) +RELOC_TYPE (FPTR64I, REL) +RELOC_TYPE (FPTR32MSB, REL|EXEC|DYN) +RELOC_TYPE (FPTR32LSB, REL|EXEC|DYN) +RELOC_TYPE (FPTR64MSB, REL|EXEC|DYN) +RELOC_TYPE (FPTR64LSB, REL|EXEC|DYN) +RELOC_TYPE (PCREL60B, REL) +RELOC_TYPE (PCREL21B, REL) +RELOC_TYPE (PCREL21M, REL) +RELOC_TYPE (PCREL21F, REL) +RELOC_TYPE (PCREL32MSB, REL|EXEC|DYN) +RELOC_TYPE (PCREL32LSB, REL|EXEC|DYN) +RELOC_TYPE (PCREL64MSB, REL|EXEC|DYN) +RELOC_TYPE (PCREL64LSB, REL|EXEC|DYN) +RELOC_TYPE (LTOFF_FPTR22, REL) +RELOC_TYPE (LTOFF_FPTR64I, REL) +RELOC_TYPE (LTOFF_FPTR32MSB, REL) +RELOC_TYPE (LTOFF_FPTR32LSB, REL) +RELOC_TYPE (LTOFF_FPTR64MSB, REL) +RELOC_TYPE (LTOFF_FPTR64LSB, REL) +RELOC_TYPE (SEGREL32MSB, REL) +RELOC_TYPE (SEGREL32LSB, REL) +RELOC_TYPE (SEGREL64MSB, REL) +RELOC_TYPE (SEGREL64LSB, REL) +RELOC_TYPE (SECREL32MSB, REL) +RELOC_TYPE (SECREL32LSB, REL) +RELOC_TYPE (SECREL64MSB, REL) +RELOC_TYPE (SECREL64LSB, REL) +RELOC_TYPE (REL32MSB, EXEC|DYN) +RELOC_TYPE (REL32LSB, EXEC|DYN) +RELOC_TYPE (REL64MSB, EXEC|DYN) +RELOC_TYPE (REL64LSB, EXEC|DYN) +RELOC_TYPE (LTV32MSB, REL) +RELOC_TYPE (LTV32LSB, REL) +RELOC_TYPE (LTV64MSB, REL) +RELOC_TYPE (LTV64LSB, REL) +RELOC_TYPE (PCREL21BI, REL) +RELOC_TYPE (PCREL22, REL) +RELOC_TYPE (PCREL64I, REL) +RELOC_TYPE (IPLTMSB, REL|EXEC|DYN) +RELOC_TYPE (IPLTLSB, REL|EXEC|DYN) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (SUB, 0) +RELOC_TYPE (LTOFF22X, REL) +RELOC_TYPE (LDXMOV, REL) +RELOC_TYPE (TPREL14, REL) +RELOC_TYPE (TPREL22, REL) +RELOC_TYPE (TPREL64I, REL) +RELOC_TYPE (TPREL64MSB, REL|EXEC|DYN) +RELOC_TYPE (TPREL64LSB, REL|EXEC|DYN) +RELOC_TYPE (LTOFF_TPREL22, REL) +RELOC_TYPE (DTPMOD64MSB, REL|EXEC|DYN) +RELOC_TYPE (DTPMOD64LSB, REL|EXEC|DYN) +RELOC_TYPE (LTOFF_DTPMOD22, REL) +RELOC_TYPE (DTPREL14, REL) +RELOC_TYPE (DTPREL22, REL) +RELOC_TYPE (DTPREL64I, REL) +RELOC_TYPE (DTPREL32MSB, REL|EXEC|DYN) +RELOC_TYPE (DTPREL32LSB, REL|EXEC|DYN) +RELOC_TYPE (DTPREL64MSB, REL|EXEC|DYN) +RELOC_TYPE (DTPREL64LSB, REL|EXEC|DYN) +RELOC_TYPE (LTOFF_DTPREL22, REL) + +#define NO_RELATIVE_RELOC 1 diff --git a/backends/ia64_retval.c b/backends/ia64_retval.c new file mode 100644 index 00000000..b5928c58 --- /dev/null +++ b/backends/ia64_retval.c @@ -0,0 +1,363 @@ +/* Function return value location for IA64 ABI. + Copyright (C) 2006-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND ia64_ +#include "libebl_CPU.h" + + +/* r8, or pair r8, r9, or aggregate up to r8-r11. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 }, + }; +#define nloc_intreg 1 +#define nloc_intregs(n) (2 * (n)) + +/* f8, or aggregate up to f8-f15. */ +#define DEFINE_FPREG(size) \ + static const Dwarf_Op loc_fpreg_##size[] = \ + { \ + { .atom = DW_OP_regx, .number = 128 + 8 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 9 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 10 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 11 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 12 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 13 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 14 }, \ + { .atom = DW_OP_piece, .number = size }, \ + { .atom = DW_OP_regx, .number = 128 + 15 }, \ + { .atom = DW_OP_piece, .number = size }, \ + } +#define nloc_fpreg 1 +#define nloc_fpregs(n) (2 * (n)) + +DEFINE_FPREG (4); +DEFINE_FPREG (8); +DEFINE_FPREG (10); + +#undef DEFINE_FPREG + + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r8. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg8, .number = 0 } + }; +#define nloc_aggregate 1 + + +/* If this type is an HFA small enough to be returned in FP registers, + return the number of registers to use. Otherwise 9, or -1 for errors. */ +static int +hfa_type (Dwarf_Die *typedie, Dwarf_Word size, + const Dwarf_Op **locp, int fpregs_used) +{ + /* Descend the type structure, counting elements and finding their types. + If we find a datum that's not an FP type (and not quad FP), punt. + If we find a datum that's not the same FP type as the first datum, punt. + If we count more than eight total homogeneous FP data, punt. */ + + inline int hfa (const Dwarf_Op *loc, int nregs) + { + if (fpregs_used == 0) + *locp = loc; + else if (*locp != loc) + return 9; + return fpregs_used + nregs; + } + + int tag = DWARF_TAG_OR_RETURN (typedie); + switch (tag) + { + Dwarf_Attribute attr_mem; + + case -1: + return -1; + + case DW_TAG_base_type:; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_float: + switch (size) + { + case 4: /* float */ + return hfa (loc_fpreg_4, 1); + case 8: /* double */ + return hfa (loc_fpreg_8, 1); + case 10: /* x86-style long double, not really used */ + return hfa (loc_fpreg_10, 1); + } + break; + + case DW_ATE_complex_float: + switch (size) + { + case 4 * 2: /* complex float */ + return hfa (loc_fpreg_4, 2); + case 8 * 2: /* complex double */ + return hfa (loc_fpreg_8, 2); + case 10 * 2: /* complex long double (x86-style) */ + return hfa (loc_fpreg_10, 2); + } + break; + } + break; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type:; + Dwarf_Die child_mem; + switch (dwarf_child (typedie, &child_mem)) + { + default: + return -1; + + case 1: /* No children: empty struct. */ + break; + + case 0:; /* Look at each element. */ + int max_used = fpregs_used; + do + switch (dwarf_tag (&child_mem)) + { + case -1: + return -1; + + case DW_TAG_member:; + Dwarf_Die child_type_mem; + Dwarf_Die *child_typedie + = dwarf_formref_die (dwarf_attr_integrate (&child_mem, + DW_AT_type, + &attr_mem), + &child_type_mem); + Dwarf_Word child_size; + if (dwarf_aggregate_size (child_typedie, &child_size) != 0) + return -1; + if (tag == DW_TAG_union_type) + { + int used = hfa_type (child_typedie, child_size, + locp, fpregs_used); + if (used < 0 || used > 8) + return used; + if (used > max_used) + max_used = used; + } + else + { + fpregs_used = hfa_type (child_typedie, child_size, + locp, fpregs_used); + if (fpregs_used < 0 || fpregs_used > 8) + return fpregs_used; + } + } + while (dwarf_siblingof (&child_mem, &child_mem) == 0); + if (tag == DW_TAG_union_type) + fpregs_used = max_used; + break; + } + break; + + case DW_TAG_array_type: + if (size == 0) + break; + + Dwarf_Die base_type_mem; + Dwarf_Die *base_typedie + = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type, + &attr_mem), + &base_type_mem); + Dwarf_Word base_size; + if (dwarf_aggregate_size (base_typedie, &base_size) != 0) + return -1; + + int used = hfa_type (base_typedie, base_size, locp, 0); + if (used < 0 || used > 8) + return used; + if (size % (*locp)[1].number != 0) + return 0; + fpregs_used += used * (size / (*locp)[1].number); + break; + + default: + return 9; + } + + return fpregs_used; +} + +int +ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + } + + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_float: + switch (size) + { + case 4: /* float */ + *locp = loc_fpreg_4; + return nloc_fpreg; + case 8: /* double */ + *locp = loc_fpreg_8; + return nloc_fpreg; + case 10: /* x86-style long double, not really used */ + *locp = loc_fpreg_10; + return nloc_fpreg; + case 16: /* long double, IEEE quad format */ + *locp = loc_intreg; + return nloc_intregs (2); + } + return -2; + + case DW_ATE_complex_float: + switch (size) + { + case 4 * 2: /* complex float */ + *locp = loc_fpreg_4; + return nloc_fpregs (2); + case 8 * 2: /* complex double */ + *locp = loc_fpreg_8; + return nloc_fpregs (2); + case 10 * 2: /* complex long double (x86-style) */ + *locp = loc_fpreg_10; + return nloc_fpregs (2); + case 16 * 2: /* complex long double (IEEE quad) */ + *locp = loc_intreg; + return nloc_intregs (4); + } + return -2; + } + } + + intreg: + *locp = loc_intreg; + if (size <= 8) + return nloc_intreg; + if (size <= 32) + return nloc_intregs ((size + 7) / 8); + + large: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_aggregate_size (typedie, &size) != 0) + return -1; + + /* If this qualifies as an homogeneous floating-point aggregate + (HFA), then it should be returned in FP regs. */ + int nfpreg = hfa_type (typedie, size, locp, 0); + if (nfpreg < 0) + return nfpreg; + else if (nfpreg > 0 && nfpreg <= 8) + return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg); + + if (size > 32) + goto large; + + goto intreg; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/ia64_symbol.c b/backends/ia64_symbol.c new file mode 100644 index 00000000..f928b0b7 --- /dev/null +++ b/backends/ia64_symbol.c @@ -0,0 +1,157 @@ +/* IA-64 specific symbolic name handling. + Copyright (C) 2002-2009, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> +#include <assert.h> + +#define BACKEND ia64_ +#include "libebl_CPU.h" + + +const char * +ia64_segment_type_name (int segment, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (segment) + { + case PT_IA_64_ARCHEXT: + return "IA_64_ARCHEXT"; + case PT_IA_64_UNWIND: + return "IA_64_UNWIND"; + case PT_IA_64_HP_OPT_ANOT: + return "IA_64_HP_OPT_ANOT"; + case PT_IA_64_HP_HSL_ANOT: + return "IA_64_HP_HSL_ANOT"; + case PT_IA_64_HP_STACK: + return "IA_64_HP_STACK"; + default: + break; + } + return NULL; +} + +const char * +ia64_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_IA_64_PLT_RESERVE: + return "IA_64_PLT_RESERVE"; + default: + break; + } + return NULL; +} + +/* Check dynamic tag. */ +bool +ia64_dynamic_tag_check (int64_t tag) +{ + return tag == DT_IA_64_PLT_RESERVE; +} + +/* Check whether machine flags are valid. */ +bool +ia64_machine_flag_check (GElf_Word flags) +{ + return ((flags &~ EF_IA_64_ABI64) == 0); +} + +/* Check whether SHF_MASKPROC flags are valid. */ +bool +ia64_machine_section_flag_check (GElf_Xword sh_flags) +{ + return (sh_flags &~ (SHF_IA_64_SHORT | SHF_IA_64_NORECOV)) == 0; +} + +/* Return symbolic representation of section type. */ +const char * +ia64_section_type_name (int type, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (type) + { + case SHT_IA_64_EXT: + return "IA_64_EXT"; + case SHT_IA_64_UNWIND: + return "IA_64_UNWIND"; + } + + return NULL; +} + +/* Check for the simple reloc types. */ +Elf_Type +ia64_reloc_simple_type (Ebl *ebl, int type) +{ + switch (type) + { + /* The SECREL types when used with non-allocated sections + like .debug_* are the same as direct absolute relocs + applied to those sections, since a 0 section address is assumed. + So we treat them the same here. */ + + case R_IA64_SECREL32MSB: + case R_IA64_DIR32MSB: + if (ebl->data == ELFDATA2MSB) + return ELF_T_WORD; + break; + case R_IA64_SECREL32LSB: + case R_IA64_DIR32LSB: + if (ebl->data == ELFDATA2LSB) + return ELF_T_WORD; + break; + case R_IA64_DIR64MSB: + case R_IA64_SECREL64MSB: + if (ebl->data == ELFDATA2MSB) + return ELF_T_XWORD; + break; + case R_IA64_SECREL64LSB: + case R_IA64_DIR64LSB: + if (ebl->data == ELFDATA2LSB) + return ELF_T_XWORD; + break; + } + + return ELF_T_NUM; +} + +/* The SHT_IA_64_UNWIND section type is a valid target for relocation. */ +bool +ia64_check_reloc_target_type (Ebl *ebl __attribute__ ((unused)), Elf64_Word sh_type) +{ + return sh_type == SHT_IA_64_UNWIND; +} diff --git a/backends/libebl_CPU.h b/backends/libebl_CPU.h new file mode 100644 index 00000000..ef2b922b --- /dev/null +++ b/backends/libebl_CPU.h @@ -0,0 +1,76 @@ +/* Common interface for libebl modules. + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifndef _LIBEBL_CPU_H +#define _LIBEBL_CPU_H 1 + +#include <dwarf.h> +#include <libeblP.h> + +#define EBLHOOK(name) EBLHOOK_1(BACKEND, name) +#define EBLHOOK_1(a, b) EBLHOOK_2(a, b) +#define EBLHOOK_2(a, b) a##b + +/* Constructor. */ +extern const char *EBLHOOK(init) (Elf *elf, GElf_Half machine, + Ebl *eh, size_t ehlen); + +#include "ebl-hooks.h" + +#define HOOK(eh, name) eh->name = EBLHOOK(name) + +extern bool (*generic_debugscn_p) (const char *) attribute_hidden; + +/* Helper for retval. Return dwarf_tag (die), but calls return -1 + if there where previous errors that leave die NULL. */ +#define DWARF_TAG_OR_RETURN(die) \ + ({ Dwarf_Die *_die = (die); \ + if (_die == NULL) return -1; \ + dwarf_tag (_die); }) + +/* Get a type die corresponding to DIE. Peel CV qualifiers off + it. */ +static inline int +dwarf_peeled_die_type (Dwarf_Die *die, Dwarf_Die *result) +{ + Dwarf_Attribute attr_mem; + Dwarf_Attribute *attr = dwarf_attr_integrate (die, DW_AT_type, &attr_mem); + if (attr == NULL) + /* The function has no return value, like a `void' function in C. */ + return 0; + + if (dwarf_formref_die (attr, result) == NULL) + return -1; + + if (dwarf_peel_type (result, result) != 0) + return -1; + + return DWARF_TAG_OR_RETURN (result); +} + +#endif /* libebl_CPU.h */ diff --git a/backends/linux-core-note.c b/backends/linux-core-note.c new file mode 100644 index 00000000..e3c01098 --- /dev/null +++ b/backends/linux-core-note.c @@ -0,0 +1,299 @@ +/* Common core note type descriptions for Linux. + Copyright (C) 2007-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#include <string.h> + +/* The including CPU_corenote.c file provides prstatus_regs and + defines macros ULONG, [PUG]ID_T, and ALIGN_*, TYPE_*. + + Here we describe the common layout used in <linux/elfcore.h>. */ + +#define CHAR int8_t +#define ALIGN_CHAR 1 +#define TYPE_CHAR ELF_T_BYTE +#define SHORT uint16_t +#define ALIGN_SHORT 2 +#define TYPE_SHORT ELF_T_HALF +#define INT int32_t +#define ALIGN_INT 4 +#define TYPE_INT ELF_T_SWORD +#ifndef ALIGN_PR_REG +# define ALIGN_PR_REG ALIGN_ULONG +#endif + +#define FIELD(type, name) type name __attribute__ ((aligned (ALIGN_##type))) + +struct EBLHOOK(siginfo) +{ + FIELD (INT, si_signo); + FIELD (INT, si_code); + FIELD (INT, si_errno); +}; + +struct EBLHOOK(timeval) +{ + FIELD (ULONG, tv_sec); + FIELD (ULONG, tv_usec); +}; + +/* On sparc64, tv_usec (suseconds_t) is actually 32 bits with 32 bits padding. + The 'T'|0x80 value for .format indicates this as a special kludge. */ +#if SUSECONDS_HALF +# define TIMEVAL_FIELD(name) FIELD (time, ULONG, name, 'T'|0x80, .count = 2) +#else +# define TIMEVAL_FIELD(name) FIELD (time, ULONG, name, 'T', .count = 2) +#endif + + +struct EBLHOOK(prstatus) +{ + struct EBLHOOK(siginfo) pr_info; + FIELD (SHORT, pr_cursig); + FIELD (ULONG, pr_sigpend); + FIELD (ULONG, pr_sighold); + FIELD (PID_T, pr_pid); + FIELD (PID_T, pr_ppid); + FIELD (PID_T, pr_pgrp); + FIELD (PID_T, pr_sid); + struct EBLHOOK(timeval) pr_utime; + struct EBLHOOK(timeval) pr_stime; + struct EBLHOOK(timeval) pr_cutime; + struct EBLHOOK(timeval) pr_cstime; + struct + { + FIELD (ULONG, pr_reg[PRSTATUS_REGS_SIZE / sizeof (ULONG)]); + } +#ifdef ALIGN_PR_REG + __attribute__ ((aligned (ALIGN_PR_REG))) +#endif + ; + FIELD (INT, pr_fpvalid); +}; + +#define FNAMESZ 16 +#define PRARGSZ 80 + +struct EBLHOOK(prpsinfo) +{ + FIELD (CHAR, pr_state); + FIELD (CHAR, pr_sname); + FIELD (CHAR, pr_zomb); + FIELD (CHAR, pr_nice); + FIELD (ULONG, pr_flag); + FIELD (UID_T, pr_uid); + FIELD (GID_T, pr_gid); + FIELD (PID_T, pr_pid); + FIELD (PID_T, pr_ppid); + FIELD (PID_T, pr_pgrp); + FIELD (PID_T, pr_sid); + FIELD (CHAR, pr_fname[FNAMESZ]); + FIELD (CHAR, pr_psargs[PRARGSZ]); +}; + +#undef FIELD + +#define FIELD(igroup, itype, item, fmt, ...) \ + { \ + .name = #item, \ + .group = #igroup, \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_##item), \ + .type = TYPE_##itype, \ + .format = fmt, \ + __VA_ARGS__ \ + } + +static const Ebl_Core_Item prstatus_items[] = + { + FIELD (signal, INT, info.si_signo, 'd'), + FIELD (signal, INT, info.si_code, 'd'), + FIELD (signal, INT, info.si_errno, 'd'), + FIELD (signal, SHORT, cursig, 'd'), + + /* Use different group name for a newline delimiter. */ + FIELD (signal2, ULONG, sigpend, 'B'), + FIELD (signal3, ULONG, sighold, 'B'), + FIELD (identity, PID_T, pid, 'd', .thread_identifier = true), + FIELD (identity, PID_T, ppid, 'd'), + FIELD (identity, PID_T, pgrp, 'd'), + FIELD (identity, PID_T, sid, 'd'), + TIMEVAL_FIELD (utime), + TIMEVAL_FIELD (stime), + TIMEVAL_FIELD (cutime), + TIMEVAL_FIELD (cstime), +#ifdef PRSTATUS_REGSET_ITEMS + PRSTATUS_REGSET_ITEMS, +#endif + FIELD (register, INT, fpvalid, 'd'), + }; + +#undef FIELD + +#define FIELD(igroup, itype, item, fmt, ...) \ + { \ + .name = #item, \ + .group = #igroup, \ + .offset = offsetof (struct EBLHOOK(prpsinfo), pr_##item), \ + .type = TYPE_##itype, \ + .format = fmt, \ + __VA_ARGS__ \ + } + +static const Ebl_Core_Item prpsinfo_items[] = + { + FIELD (state, CHAR, state, 'd'), + FIELD (state, CHAR, sname, 'c'), + FIELD (state, CHAR, zomb, 'd'), + FIELD (state, CHAR, nice, 'd'), + FIELD (state, ULONG, flag, 'x'), + FIELD (identity, UID_T, uid, 'd'), + FIELD (identity, GID_T, gid, 'd'), + FIELD (identity, PID_T, pid, 'd'), + FIELD (identity, PID_T, ppid, 'd'), + FIELD (identity, PID_T, pgrp, 'd'), + FIELD (identity, PID_T, sid, 'd'), + FIELD (command, CHAR, fname, 's', .count = FNAMESZ), + FIELD (command, CHAR, psargs, 's', .count = PRARGSZ), + }; + +static const Ebl_Core_Item vmcoreinfo_items[] = + { + { + .type = ELF_T_BYTE, .format = '\n' + } + }; + +#undef FIELD + +int +EBLHOOK(core_note) (nhdr, name, regs_offset, nregloc, reglocs, nitems, items) + const GElf_Nhdr *nhdr; + const char *name; + GElf_Word *regs_offset; + size_t *nregloc; + const Ebl_Register_Location **reglocs; + size_t *nitems; + const Ebl_Core_Item **items; +{ + switch (nhdr->n_namesz) + { + case sizeof "CORE" - 1: /* Buggy old Linux kernels. */ + if (memcmp (name, "CORE", nhdr->n_namesz) == 0) + break; + return 0; + + case sizeof "CORE": + if (memcmp (name, "CORE", nhdr->n_namesz) == 0) + break; + /* Buggy old Linux kernels didn't terminate "LINUX". + Fall through. */ + + case sizeof "LINUX": + if (memcmp (name, "LINUX", nhdr->n_namesz) == 0) + break; + return 0; + + case sizeof "VMCOREINFO": + if (nhdr->n_type != 0 + || memcmp (name, "VMCOREINFO", sizeof "VMCOREINFO") != 0) + return 0; + *regs_offset = 0; + *nregloc = 0; + *nitems = 1; + *items = vmcoreinfo_items; + return 1; + + default: + return 0; + } + + switch (nhdr->n_type) + { + case NT_PRSTATUS: + if (nhdr->n_descsz != sizeof (struct EBLHOOK(prstatus))) + return 0; + *regs_offset = offsetof (struct EBLHOOK(prstatus), pr_reg); + *nregloc = sizeof prstatus_regs / sizeof prstatus_regs[0]; + *reglocs = prstatus_regs; + *nitems = sizeof prstatus_items / sizeof prstatus_items[0]; + *items = prstatus_items; + return 1; + + case NT_PRPSINFO: + if (nhdr->n_descsz != sizeof (struct EBLHOOK(prpsinfo))) + return 0; + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + *nitems = sizeof prpsinfo_items / sizeof prpsinfo_items[0]; + *items = prpsinfo_items; + return 1; + +#define EXTRA_REGSET(type, size, table) \ + case type: \ + if (nhdr->n_descsz != size) \ + return 0; \ + *regs_offset = 0; \ + *nregloc = sizeof table / sizeof table[0]; \ + *reglocs = table; \ + *nitems = 0; \ + *items = NULL; \ + return 1; + +#define EXTRA_REGSET_ITEMS(type, size, table, extra_items) \ + case type: \ + if (nhdr->n_descsz != size) \ + return 0; \ + *regs_offset = 0; \ + *nregloc = sizeof table / sizeof table[0]; \ + *reglocs = table; \ + *nitems = sizeof extra_items / sizeof extra_items[0]; \ + *items = extra_items; \ + return 1; + +#define EXTRA_ITEMS(type, size, extra_items) \ + case type: \ + if (nhdr->n_descsz != size) \ + return 0; \ + *regs_offset = 0; \ + *nregloc = 0; \ + *reglocs = NULL; \ + *nitems = sizeof extra_items / sizeof extra_items[0]; \ + *items = extra_items; \ + return 1; + +#ifdef FPREGSET_SIZE + EXTRA_REGSET (NT_FPREGSET, FPREGSET_SIZE, fpregset_regs) +#endif + +#ifdef EXTRA_NOTES + EXTRA_NOTES +#endif + } + + return 0; +} diff --git a/backends/ppc64_corenote.c b/backends/ppc64_corenote.c new file mode 100644 index 00000000..9d6a6a44 --- /dev/null +++ b/backends/ppc64_corenote.c @@ -0,0 +1,2 @@ +#define BITS 64 +#include "ppc_corenote.c" diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c new file mode 100644 index 00000000..56e1828e --- /dev/null +++ b/backends/ppc64_init.c @@ -0,0 +1,109 @@ +/* Initialization of PPC64 specific backend library. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#define BACKEND ppc64_ +#define RELOC_PREFIX R_PPC64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on ppc64_reloc.def. */ +#include "common-reloc.c" + + +const char * +ppc64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "PowerPC 64-bit"; + ppc64_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, machine_flag_check); + HOOK (eh, copy_reloc_p); + HOOK (eh, check_special_symbol); + HOOK (eh, check_st_other_bits); + HOOK (eh, bss_plt_p); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, syscall_abi); + HOOK (eh, core_note); + HOOK (eh, auxv_info); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = (114 - 1) + 32; + HOOK (eh, set_initial_registers_tid); + HOOK (eh, dwarf_to_regno); + HOOK (eh, resolve_sym_value); + + /* Find the function descriptor .opd table for resolve_sym_value. */ + if (elf != NULL) + { + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); + if (ehdr != NULL && ehdr->e_type != ET_REL) + { + /* We could also try through DT_PPC64_OPD and DT_PPC64_OPDSZ. */ + GElf_Shdr opd_shdr_mem, *opd_shdr; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + opd_shdr = gelf_getshdr (scn, &opd_shdr_mem); + if (opd_shdr != NULL + && (opd_shdr->sh_flags & SHF_ALLOC) != 0 + && opd_shdr->sh_type == SHT_PROGBITS + && opd_shdr->sh_size > 0) + { + const char *name = elf_strptr (elf, ehdr->e_shstrndx, + opd_shdr->sh_name); + if (name != NULL && strcmp (name, ".opd") == 0) + { + eh->fd_addr = opd_shdr->sh_addr; + eh->fd_data = elf_getdata (scn, NULL); + break; + } + } + } + } + } + + return MODVERSION; +} diff --git a/backends/ppc64_reloc.def b/backends/ppc64_reloc.def new file mode 100644 index 00000000..3a693cf6 --- /dev/null +++ b/backends/ppc64_reloc.def @@ -0,0 +1,161 @@ +/* List the relocation types for ppc64. -*- C -*- + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (ADDR32, REL|EXEC|DYN) +RELOC_TYPE (ADDR24, REL) +RELOC_TYPE (ADDR16, REL) /* note 1 */ +RELOC_TYPE (ADDR16_LO, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HI, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HA, REL) /* note 1 */ +RELOC_TYPE (ADDR14, REL) /* note 1 */ +RELOC_TYPE (ADDR14_BRTAKEN, REL) /* note 1 */ +RELOC_TYPE (ADDR14_BRNTAKEN, REL) /* note 1 */ +RELOC_TYPE (REL24, REL) +RELOC_TYPE (REL14, REL) +RELOC_TYPE (REL14_BRTAKEN, REL) +RELOC_TYPE (REL14_BRNTAKEN, REL) +RELOC_TYPE (GOT16, REL) +RELOC_TYPE (GOT16_LO, REL) +RELOC_TYPE (GOT16_HI, REL) +RELOC_TYPE (GOT16_HA, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (UADDR32, REL|EXEC|DYN) +RELOC_TYPE (UADDR16, REL) +RELOC_TYPE (REL32, REL|EXEC|DYN) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (PLTREL32, REL) +RELOC_TYPE (PLT16_LO, REL) +RELOC_TYPE (PLT16_HI, REL) +RELOC_TYPE (PLT16_HA, REL) +RELOC_TYPE (SECTOFF, REL) +RELOC_TYPE (SECTOFF_LO, REL) +RELOC_TYPE (SECTOFF_HI, REL) +RELOC_TYPE (SECTOFF_HA, REL) +RELOC_TYPE (ADDR30, REL) /* note 1 */ +RELOC_TYPE (ADDR64, REL|EXEC|DYN) +RELOC_TYPE (ADDR16_HIGHER, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HIGHERA, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HIGHEST, REL) /* note 1 */ +RELOC_TYPE (ADDR16_HIGHESTA, REL) /* note 1 */ +RELOC_TYPE (UADDR64, REL|EXEC|DYN) +RELOC_TYPE (REL64, REL|EXEC|DYN) +RELOC_TYPE (PLT64, REL) +RELOC_TYPE (PLTREL64, REL) +RELOC_TYPE (TOC16, REL) +RELOC_TYPE (TOC16_LO, REL) +RELOC_TYPE (TOC16_HI, REL) +RELOC_TYPE (TOC16_HA, REL) +RELOC_TYPE (TOC, REL) +RELOC_TYPE (PLTGOT16, REL) +RELOC_TYPE (PLTGOT16_LO, REL) +RELOC_TYPE (PLTGOT16_HI, REL) +RELOC_TYPE (PLTGOT16_HA, REL) +RELOC_TYPE (ADDR16_DS, REL) /* note 1 */ +RELOC_TYPE (ADDR16_LO_DS, REL) /* note 1 */ +RELOC_TYPE (GOT16_DS, REL) +RELOC_TYPE (GOT16_LO_DS, REL) +RELOC_TYPE (PLT16_LO_DS, REL) +RELOC_TYPE (SECTOFF_DS, REL) +RELOC_TYPE (SECTOFF_LO_DS, REL) +RELOC_TYPE (TOC16_DS, REL) +RELOC_TYPE (TOC16_LO_DS, REL) +RELOC_TYPE (PLTGOT16_DS, REL) +RELOC_TYPE (PLTGOT16_LO_DS, REL) +RELOC_TYPE (TLS, REL) +RELOC_TYPE (DTPMOD64, REL|EXEC|DYN) /* note 3 */ +RELOC_TYPE (TPREL16, REL) /* note 2 */ +RELOC_TYPE (TPREL16_LO, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HI, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HA, REL) /* note 2 */ +RELOC_TYPE (TPREL64, REL|EXEC|DYN) /* note 3 */ +RELOC_TYPE (DTPREL16, REL) +RELOC_TYPE (DTPREL16_LO, REL) +RELOC_TYPE (DTPREL16_HI, REL) +RELOC_TYPE (DTPREL16_HA, REL) +RELOC_TYPE (DTPREL64, REL|EXEC|DYN) /* note 3 */ +RELOC_TYPE (GOT_TLSGD16, REL) +RELOC_TYPE (GOT_TLSGD16_LO, REL) +RELOC_TYPE (GOT_TLSGD16_HI, REL) +RELOC_TYPE (GOT_TLSGD16_HA, REL) +RELOC_TYPE (GOT_TLSLD16, REL) +RELOC_TYPE (GOT_TLSLD16_LO, REL) +RELOC_TYPE (GOT_TLSLD16_HI, REL) +RELOC_TYPE (GOT_TLSLD16_HA, REL) +RELOC_TYPE (GOT_TPREL16_DS, REL) +RELOC_TYPE (GOT_TPREL16_LO_DS, REL) +RELOC_TYPE (GOT_TPREL16_HI, REL) +RELOC_TYPE (GOT_TPREL16_HA, REL) +RELOC_TYPE (GOT_DTPREL16_DS, REL) +RELOC_TYPE (GOT_DTPREL16_LO_DS, REL) +RELOC_TYPE (GOT_DTPREL16_HI, REL) +RELOC_TYPE (GOT_DTPREL16_HA, REL) +RELOC_TYPE (TPREL16_DS, REL) /* note 2 */ +RELOC_TYPE (TPREL16_LO_DS, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HIGHER, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HIGHERA, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HIGHEST, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HIGHESTA, REL) /* note 2 */ +RELOC_TYPE (DTPREL16_DS, REL) +RELOC_TYPE (DTPREL16_LO_DS, REL) +RELOC_TYPE (DTPREL16_HIGHER, REL) +RELOC_TYPE (DTPREL16_HIGHERA, REL) +RELOC_TYPE (DTPREL16_HIGHEST, REL) +RELOC_TYPE (DTPREL16_HIGHESTA, REL) +RELOC_TYPE (TLSGD, REL) +RELOC_TYPE (TLSLD, REL) +RELOC_TYPE (TOCSAVE, REL) +RELOC_TYPE (ADDR16_HIGH, REL) +RELOC_TYPE (ADDR16_HIGHA, REL) +RELOC_TYPE (TPREL16_HIGH, REL) +RELOC_TYPE (TPREL16_HIGHA, REL) +RELOC_TYPE (DTPREL16_HIGH, REL) +RELOC_TYPE (DTPREL16_HIGHA, REL) +RELOC_TYPE (JMP_IREL, REL) +RELOC_TYPE (IRELATIVE, REL) +RELOC_TYPE (REL16, REL) +RELOC_TYPE (REL16_LO, REL) +RELOC_TYPE (REL16_HI, REL) +RELOC_TYPE (REL16_HA, REL) + +/* Notes from Alan Modra: + + 1) These can appear in DYN and EXEC with improper assembly, but they + aren't really kosher. + + 2) These can appear in DYN with improper assembly (or silly gcc + attributes, I think). Again, not kosher. + + 3) These are legal in REL for PowerOpen compatible assembler syntax, + ie. TOC managed by compiler. +*/ diff --git a/backends/ppc64_resolve_sym.c b/backends/ppc64_resolve_sym.c new file mode 100644 index 00000000..03f65584 --- /dev/null +++ b/backends/ppc64_resolve_sym.c @@ -0,0 +1,63 @@ +/* Resolve symbol values through .opd function descriptors. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc64_ +#include "libebl_CPU.h" + +/* Resolve a function descriptor if addr points into the .opd section. + The .opd section contains function descriptors consisting of 3 addresses. + function, toc and chain. We are just interested in the first. + http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#FUNC-DES + + Returns true if the given address could be resolved, false otherwise. +*/ +bool +ppc64_resolve_sym_value (Ebl *ebl, GElf_Addr *addr) +{ + if (ebl->fd_data != NULL && *addr >= ebl->fd_addr + && *addr + sizeof (Elf64_Addr) <= ebl->fd_addr + ebl->fd_data->d_size) + { + GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (ebl->elf, &ehdr_mem); + if (ehdr != NULL) + { + Elf_Data opd_in, opd_out; + opd_in.d_buf = ebl->fd_data->d_buf + (*addr - ebl->fd_addr); + opd_out.d_buf = addr; + opd_out.d_size = opd_in.d_size = sizeof (Elf64_Addr); + opd_out.d_type = opd_in.d_type = ELF_T_ADDR; + if (elf64_xlatetom (&opd_out, &opd_in, + ehdr->e_ident[EI_DATA]) != NULL) + return true; + } + } + return false; +} diff --git a/backends/ppc64_retval.c b/backends/ppc64_retval.c new file mode 100644 index 00000000..a2519839 --- /dev/null +++ b/backends/ppc64_retval.c @@ -0,0 +1,195 @@ +/* Function return value location for Linux/PPC64 ABI. + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND ppc64_ +#include "libebl_CPU.h" + + +/* r3. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg3 } + }; +#define nloc_intreg 1 + +/* f1, or f1:f2, or f1:f4. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_regx, .number = 36 }, { .atom = DW_OP_piece, .number = 8 }, + }; +#define nloc_fpreg 1 +#define nloc_fp2regs 4 +#define nloc_fp4regs 8 + +/* vr2. */ +static const Dwarf_Op loc_vmxreg[] = + { + { .atom = DW_OP_regx, .number = 1124 + 2 } + }; +#define nloc_vmxreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r3. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg3, .number = 0 } + }; +#define nloc_aggregate 1 + +int +ppc64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + } + + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + if (encoding == DW_ATE_float || encoding == DW_ATE_complex_float) + { + *locp = loc_fpreg; + if (size <= 8) + return nloc_fpreg; + if (size <= 16) + return nloc_fp2regs; + if (size <= 32) + return nloc_fp4regs; + } + } + if (size <= 8) + { + intreg: + *locp = loc_intreg; + return nloc_intreg; + } + + /* Else fall through. */ + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_array_type: + { + Dwarf_Attribute attr_mem; + bool is_vector; + if (dwarf_formflag (dwarf_attr_integrate (typedie, DW_AT_GNU_vector, + &attr_mem), &is_vector) == 0 + && is_vector) + { + *locp = loc_vmxreg; + return nloc_vmxreg; + } + } + /* Fall through. */ + + case DW_TAG_string_type: + if (dwarf_aggregate_size (typedie, &size) == 0 && size <= 8) + { + if (tag == DW_TAG_array_type) + { + /* Check if it's a character array. */ + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + if (tag != DW_TAG_base_type) + goto aggregate; + if (dwarf_formudata (dwarf_attr_integrate (typedie, + DW_AT_byte_size, + &attr_mem), + &size) != 0) + return -1; + if (size != 1) + goto aggregate; + } + goto intreg; + } + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/ppc64_symbol.c b/backends/ppc64_symbol.c new file mode 100644 index 00000000..0feddcee --- /dev/null +++ b/backends/ppc64_symbol.c @@ -0,0 +1,130 @@ +/* PPC64 specific symbolic name handling. + Copyright (C) 2004, 2005, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND ppc64_ +#include "libebl_CPU.h" + + +/* Check for the simple reloc types. */ +Elf_Type +ppc64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_PPC64_ADDR64: + case R_PPC64_UADDR64: + return ELF_T_XWORD; + case R_PPC64_ADDR32: + case R_PPC64_UADDR32: + return ELF_T_WORD; + case R_PPC64_UADDR16: + return ELF_T_HALF; + default: + return ELF_T_NUM; + } +} + + +const char * +ppc64_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_PPC64_GLINK: + return "PPC64_GLINK"; + case DT_PPC64_OPD: + return "PPC64_OPD"; + case DT_PPC64_OPDSZ: + return "PPC64_OPDSZ"; + case DT_PPC64_OPT: + return "PPC64_OPT"; + default: + break; + } + return NULL; +} + + +bool +ppc64_dynamic_tag_check (int64_t tag) +{ + return (tag == DT_PPC64_GLINK + || tag == DT_PPC64_OPD + || tag == DT_PPC64_OPDSZ + || tag == DT_PPC64_OPT); +} + + +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +bool +ppc64_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, + const GElf_Sym *sym __attribute__ ((unused)), + const char *name __attribute__ ((unused)), + const GElf_Shdr *destshdr) +{ + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname == NULL) + return false; + return strcmp (sname, ".opd") == 0; +} + + +/* Check if backend uses a bss PLT in this file. */ +bool +ppc64_bss_plt_p (Elf *elf __attribute__ ((unused))) +{ + return true; +} + +/* Check whether machine flags are valid. PPC64 has three possible values: + 0 - for unspecified ABI, or not using any specific ABI features. + 1 - for the original ELF PPC64 ABI using function descriptors. + 2 - for the revised ELFv2 PPC64 ABI without function descriptors. */ +bool +ppc64_machine_flag_check (GElf_Word flags) +{ + return flags == 0 || flags == 1 || flags == 2; +} + +bool +ppc64_check_st_other_bits (unsigned char st_other) +{ + return (PPC64_LOCAL_ENTRY_OFFSET (st_other) != 0); +} diff --git a/backends/ppc_attrs.c b/backends/ppc_attrs.c new file mode 100644 index 00000000..ebeafe5a --- /dev/null +++ b/backends/ppc_attrs.c @@ -0,0 +1,89 @@ +/* Object attribute tags for PowerPC. + Copyright (C) 2008, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +bool +ppc_check_object_attribute (ebl, vendor, tag, value, tag_name, value_name) + Ebl *ebl __attribute__ ((unused)); + const char *vendor; + int tag; + uint64_t value; + const char **tag_name; + const char **value_name; +{ + if (!strcmp (vendor, "gnu")) + switch (tag) + { + case 4: + *tag_name = "GNU_Power_ABI_FP"; + static const char *fp_kinds[] = + { + "Hard or soft float", + "Hard float", + "Soft float", + }; + if (value < sizeof fp_kinds / sizeof fp_kinds[0]) + *value_name = fp_kinds[value]; + return true; + + case 8: + *tag_name = "GNU_Power_ABI_Vector"; + static const char *vector_kinds[] = + { + "Any", "Generic", "AltiVec", "SPE" + }; + if (value < sizeof vector_kinds / sizeof vector_kinds[0]) + *value_name = vector_kinds[value]; + return true; + + case 12: + *tag_name = "GNU_Power_ABI_Struct_Return"; + static const char *struct_return_kinds[] = + { + "Any", "r3/r4", "Memory" + }; + if (value < sizeof struct_return_kinds / sizeof struct_return_kinds[0]) + *value_name = struct_return_kinds[value]; + return true; + } + + return false; +} + +__typeof (ppc_check_object_attribute) + ppc64_check_object_attribute + __attribute__ ((alias ("ppc_check_object_attribute"))); diff --git a/backends/ppc_auxv.c b/backends/ppc_auxv.c new file mode 100644 index 00000000..a27a1da4 --- /dev/null +++ b/backends/ppc_auxv.c @@ -0,0 +1,55 @@ +/* i386 specific auxv handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "ppcle\0" "truele\0" "3\0" "4\0" "5\0" "6\0" "7\0" "8\0" "9\0" + "power6x\0" "dfp\0" "pa6t\0" "arch_2_05\0" + "ic_snoop\0" "smt\0" "booke\0" "cellbe\0" + "power5+\0" "power5\0" "power4\0" "notb\0" + "efpdouble\0" "efpsingle\0" "spe\0" "ucache\0" + "4xxmac\0" "mmu\0" "fpu\0" "altivec\0" + "ppc601\0" "ppc64\0" "ppc32\0" "\0"; + return 1; +} + +__typeof (ppc_auxv_info) ppc64_auxv_info + __attribute__ ((alias ("ppc_auxv_info"))); diff --git a/backends/ppc_cfi.c b/backends/ppc_cfi.c new file mode 100644 index 00000000..55169aef --- /dev/null +++ b/backends/ppc_cfi.c @@ -0,0 +1,77 @@ +/* ppc ABI-specified defaults for DWARF CFI. + Copyright (C) 2012, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +int +ppc_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* This instruction is provided in every CIE. It is not repeated here: + DW_CFA_def_cfa, ULEB128_7 (1), ULEB128_7 (0) */ + /* r1 is assumed to be restored from cfa adress, + r1 acts as a stack frame pointer. */ + DW_CFA_val_offset, ULEB128_7 (1), ULEB128_7 (0), + /* lr is not callee-saved but it needs to be preserved as it is pre-set + by the caller. */ + DW_CFA_same_value, ULEB128_7 (65), /* lr */ + + /* Callee-saved regs. */ +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + SV (2), /* r2 is TOC pointer. */ + SV (13), /* Reserved as system thread id (is it for CFI?). */ + /* r14-r31 are non-volatile registers. */ + SV (14), SV (15), SV (16), SV (17), SV (18), SV (19), SV (20), SV (21), + SV (22), SV (23), SV (24), SV (25), SV (26), SV (27), SV (28), SV (29), + SV (30), SV (31) + /* VMX registers v20-v31 and vrsave are non-volatile but they are + assigned DWARF registers 1144-1156 (v20-v31) which is outside of the + CFI supported range. */ +#undef SV + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = ebl->class == ELFCLASS64 ? 8 : 4; + + abi_info->return_address_register = 65; + + return 0; +} + +__typeof (ppc_abi_cfi) + ppc64_abi_cfi + __attribute__ ((alias ("ppc_abi_cfi"))); diff --git a/backends/ppc_corenote.c b/backends/ppc_corenote.c new file mode 100644 index 00000000..9ac88712 --- /dev/null +++ b/backends/ppc_corenote.c @@ -0,0 +1,134 @@ +/* PowerPC specific core note handling. + Copyright (C) 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#ifndef BITS +# define BITS 32 +# define BACKEND ppc_ +#else +# define BITS 64 +# define BACKEND ppc64_ +#endif +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = BITS } + + GR (0, 32, 0), /* r0-r31 */ + /* 32, 1, nip */ + GR (33, 1, 66), /* msr */ + /* 34, 1, orig_gpr3 */ + GR (35, 1, 109), /* ctr */ + GR (36, 1, 108), /* lr */ + GR (37, 1, 101), /* xer */ + GR (38, 1, 64), /* cr */ + GR (39, 1, 100), /* mq */ + /* 40, 1, trap */ + GR (41, 1, 119), /* dar */ + GR (42, 1, 118), /* dsisr */ + +#undef GR + }; +#define PRSTATUS_REGS_SIZE (BITS / 8 * 48) + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 32, .count = 32, .bits = 64 }, /* f0-f31 */ + { .offset = 32 * 8 + 4, .regno = 65, .count = 1, .bits = 32 } /* fpscr */ + }; +#define FPREGSET_SIZE (33 * 8) + +static const Ebl_Register_Location altivec_regs[] = + { + /* vr0-vr31 */ + { .offset = 0, .regno = 1124, .count = 32, .bits = 128 }, + /* vscr XXX 67 is an unofficial assignment */ + { .offset = 32 * 16, .regno = 67, .count = 1, .bits = 32, .pad = 12 }, + /* vrsave */ + { .offset = 33 * 16, .regno = 356, .count = 1, .bits = 32, .pad = 12 } + }; + +static const Ebl_Register_Location spe_regs[] = + { + /* evr0-evr31 + { .offset = 0, .regno = ???, .count = 32, .bits = 32 }, + * acc * + { .offset = 32 * 4, .regno = ???, .count = 1, .bits = 64 }, */ + /* spefscr */ + { .offset = 34 * 4, .regno = 612, .count = 1, .bits = 32 } + }; + +#define EXTRA_NOTES \ + EXTRA_REGSET (NT_PPC_VMX, 34 * 16, altivec_regs) \ + EXTRA_REGSET (NT_PPC_SPE, 35 * 4, spe_regs) + +#if BITS == 32 +# define ULONG uint32_t +# define ALIGN_ULONG 4 +# define TYPE_ULONG ELF_T_WORD +# define TYPE_LONG ELF_T_SWORD +#else +# define ULONG uint64_t +# define ALIGN_ULONG 8 +# define TYPE_ULONG ELF_T_XWORD +# define TYPE_LONG ELF_T_SXWORD +#endif +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "nip", .type = ELF_T_ADDR, .format = 'x', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[32]), \ + .group = "register", .pc_register = true \ + }, \ + { \ + .name = "orig_gpr3", .type = TYPE_LONG, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[34]), \ + .group = "register" \ + } + +#include "linux-core-note.c" diff --git a/backends/ppc_init.c b/backends/ppc_init.c new file mode 100644 index 00000000..ad92765c --- /dev/null +++ b/backends/ppc_init.c @@ -0,0 +1,74 @@ +/* Initialization of PPC specific backend library. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc_ +#define RELOC_PREFIX R_PPC_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on ppc_reloc.def. */ +#include "common-reloc.c" + + +const char * +ppc_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "PowerPC"; + ppc_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + HOOK (eh, check_special_symbol); + HOOK (eh, bss_plt_p); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, syscall_abi); + HOOK (eh, core_note); + HOOK (eh, auxv_info); + HOOK (eh, check_object_attribute); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = (114 - 1) + 32; + HOOK (eh, set_initial_registers_tid); + HOOK (eh, dwarf_to_regno); + + return MODVERSION; +} diff --git a/backends/ppc_initreg.c b/backends/ppc_initreg.c new file mode 100644 index 00000000..64f53793 --- /dev/null +++ b/backends/ppc_initreg.c @@ -0,0 +1,114 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <stdlib.h> +#ifdef __powerpc__ +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +bool +ppc_dwarf_to_regno (Ebl *ebl __attribute__ ((unused)), unsigned *regno) +{ + switch (*regno) + { + case 108: + // LR uses both 65 and 108 numbers, there is no consistency for it. + *regno = 65; + return true; + case 0 ... 107: + case 109 ... (114 - 1) -1: + return true; + case 1200 ... 1231: + *regno = *regno - 1200 + (114 - 1); + return true; + default: + return false; + } + abort (); +} + +__typeof (ppc_dwarf_to_regno) + ppc64_dwarf_to_regno + __attribute__ ((alias ("ppc_dwarf_to_regno"))); + +bool +ppc_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __powerpc__ + return false; +#else /* __powerpc__ */ + union + { + struct pt_regs r; + long l[sizeof (struct pt_regs) / sizeof (long)]; + } + user_regs; + eu_static_assert (sizeof (struct pt_regs) % sizeof (long) == 0); + /* PTRACE_GETREGS is EIO on kernel-2.6.18-308.el5.ppc64. */ + errno = 0; + for (unsigned regno = 0; regno < sizeof (user_regs) / sizeof (long); + regno++) + { + user_regs.l[regno] = ptrace (PTRACE_PEEKUSER, tid, + (void *) (uintptr_t) (regno + * sizeof (long)), + NULL); + if (errno != 0) + return false; + } + const size_t gprs = sizeof (user_regs.r.gpr) / sizeof (*user_regs.r.gpr); + Dwarf_Word dwarf_regs[gprs]; + for (unsigned gpr = 0; gpr < gprs; gpr++) + dwarf_regs[gpr] = user_regs.r.gpr[gpr]; + if (! setfunc (0, gprs, dwarf_regs, arg)) + return false; + dwarf_regs[0] = user_regs.r.link; + // LR uses both 65 and 108 numbers, there is no consistency for it. + if (! setfunc (65, 1, dwarf_regs, arg)) + return false; + /* Registers like msr, ctr, xer, dar, dsisr etc. are probably irrelevant + for CFI. */ + dwarf_regs[0] = user_regs.r.nip; + return setfunc (-1, 1, dwarf_regs, arg); +#endif /* __powerpc__ */ +} + +__typeof (ppc_set_initial_registers_tid) + ppc64_set_initial_registers_tid + __attribute__ ((alias ("ppc_set_initial_registers_tid"))); diff --git a/backends/ppc_regs.c b/backends/ppc_regs.c new file mode 100644 index 00000000..4b92a9aa --- /dev/null +++ b/backends/ppc_regs.c @@ -0,0 +1,200 @@ +/* Register names and numbers for PowerPC DWARF. + Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +ssize_t +ppc_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 1156; + + if (regno < 0 || regno > 1155 || namelen < 8) + return -1; + + *prefix = ""; + *bits = ebl->machine == EM_PPC64 ? 64 : 32; + *type = (regno < 32 ? DW_ATE_signed + : regno < 64 ? DW_ATE_float : DW_ATE_unsigned); + + if (regno < 32 || regno == 64 || regno == 66) + *setname = "integer"; + else if (regno < 64 || regno == 65) + { + *setname = "FPU"; + if (ebl->machine != EM_PPC64 && regno < 64) + *bits = 64; + } + else if (regno == 67 || regno == 356 || regno == 612 || regno >= 1124) + { + *setname = "vector"; + *bits = regno >= 1124 ? 128 : 32; + } + else + *setname = "privileged"; + + switch (regno) + { + case 0 ... 9: + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 31: + name[0] = 'r'; + name[1] = regno / 10 + '0'; + name[2] = regno % 10 + '0'; + namelen = 3; + break; + + case 32 + 0 ... 32 + 9: + name[0] = 'f'; + name[1] = (regno - 32) + '0'; + namelen = 2; + break; + + case 32 + 10 ... 32 + 31: + name[0] = 'f'; + name[1] = (regno - 32) / 10 + '0'; + name[2] = (regno - 32) % 10 + '0'; + namelen = 3; + break; + + case 64: + return stpcpy (name, "cr") + 1 - name; + case 65: + return stpcpy (name, "fpscr") + 1 - name; + case 66: + return stpcpy (name, "msr") + 1 - name; + case 67: /* XXX unofficial assignment */ + return stpcpy (name, "vscr") + 1 - name; + + case 70 + 0 ... 70 + 9: + name[0] = 's'; + name[1] = 'r'; + name[2] = (regno - 70) + '0'; + namelen = 3; + break; + + case 70 + 10 ... 70 + 15: + name[0] = 's'; + name[1] = 'r'; + name[2] = (regno - 70) / 10 + '0'; + name[3] = (regno - 70) % 10 + '0'; + namelen = 4; + break; + + case 101: + return stpcpy (name, "xer") + 1 - name; + case 108: + return stpcpy (name, "lr") + 1 - name; + case 109: + return stpcpy (name, "ctr") + 1 - name; + case 118: + return stpcpy (name, "dsisr") + 1 - name; + case 119: + return stpcpy (name, "dar") + 1 - name; + case 122: + return stpcpy (name, "dec") + 1 - name; + case 356: + return stpcpy (name, "vrsave") + 1 - name; + case 612: + return stpcpy (name, "spefscr") + 1 - name; + case 100: + if (*bits == 32) + return stpcpy (name, "mq") + 1 - name; + + case 102 ... 107: + name[0] = 's'; + name[1] = 'p'; + name[2] = 'r'; + name[3] = (regno - 100) + '0'; + namelen = 4; + break; + + case 110 ... 117: + case 120 ... 121: + case 123 ... 199: + name[0] = 's'; + name[1] = 'p'; + name[2] = 'r'; + name[3] = (regno - 100) / 10 + '0'; + name[4] = (regno - 100) % 10 + '0'; + namelen = 5; + break; + + case 200 ... 355: + case 357 ... 611: + case 613 ... 999: + name[0] = 's'; + name[1] = 'p'; + name[2] = 'r'; + name[3] = (regno - 100) / 100 + '0'; + name[4] = ((regno - 100) % 100 / 10) + '0'; + name[5] = (regno - 100) % 10 + '0'; + namelen = 6; + break; + + case 1124 + 0 ... 1124 + 9: + name[0] = 'v'; + name[1] = 'r'; + name[2] = (regno - 1124) + '0'; + namelen = 3; + break; + + case 1124 + 10 ... 1124 + 31: + name[0] = 'v'; + name[1] = 'r'; + name[2] = (regno - 1124) / 10 + '0'; + name[3] = (regno - 1124) % 10 + '0'; + namelen = 4; + break; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} + +__typeof (ppc_register_info) + ppc64_register_info __attribute__ ((alias ("ppc_register_info"))); diff --git a/backends/ppc_reloc.def b/backends/ppc_reloc.def new file mode 100644 index 00000000..dc963a0e --- /dev/null +++ b/backends/ppc_reloc.def @@ -0,0 +1,137 @@ +/* List the relocation types for ppc. -*- C -*- + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (ADDR32, REL|EXEC|DYN) +RELOC_TYPE (ADDR24, REL) +RELOC_TYPE (ADDR16, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR16_LO, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR16_HI, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR16_HA, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR14, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR14_BRTAKEN, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (ADDR14_BRNTAKEN, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (REL24, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (REL14, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (REL14_BRTAKEN, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (REL14_BRNTAKEN, REL|EXEC|DYN) /* note 1 */ +RELOC_TYPE (GOT16, REL) +RELOC_TYPE (GOT16_LO, REL) +RELOC_TYPE (GOT16_HI, REL) +RELOC_TYPE (GOT16_HA, REL) +RELOC_TYPE (PLTREL24, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (LOCAL24PC, REL) +RELOC_TYPE (UADDR32, REL|EXEC|DYN) +RELOC_TYPE (UADDR16, REL) /* note 2 */ +RELOC_TYPE (REL32, REL|EXEC|DYN) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (PLTREL32, REL) +RELOC_TYPE (PLT16_LO, REL) +RELOC_TYPE (PLT16_HI, REL) +RELOC_TYPE (PLT16_HA, REL) +RELOC_TYPE (SDAREL16, REL) +RELOC_TYPE (SECTOFF, REL) +RELOC_TYPE (SECTOFF_LO, REL) +RELOC_TYPE (SECTOFF_HI, REL) +RELOC_TYPE (SECTOFF_HA, REL) +RELOC_TYPE (TLS, REL) +RELOC_TYPE (DTPMOD32, EXEC|DYN) /* note 2 */ +RELOC_TYPE (TPREL16, REL) /* note 2 */ +RELOC_TYPE (TPREL16_LO, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HI, REL) /* note 2 */ +RELOC_TYPE (TPREL16_HA, REL) /* note 2 */ +RELOC_TYPE (TPREL32, EXEC|DYN) /* note 2 */ +RELOC_TYPE (DTPREL16, REL) +RELOC_TYPE (DTPREL16_LO, REL) +RELOC_TYPE (DTPREL16_HI, REL) +RELOC_TYPE (DTPREL16_HA, REL) +RELOC_TYPE (DTPREL32, EXEC|DYN) /* note 2 */ +RELOC_TYPE (GOT_TLSGD16, REL) +RELOC_TYPE (GOT_TLSGD16_LO, REL) +RELOC_TYPE (GOT_TLSGD16_HI, REL) +RELOC_TYPE (GOT_TLSGD16_HA, REL) +RELOC_TYPE (GOT_TLSLD16, REL) +RELOC_TYPE (GOT_TLSLD16_LO, REL) +RELOC_TYPE (GOT_TLSLD16_HI, REL) +RELOC_TYPE (GOT_TLSLD16_HA, REL) +RELOC_TYPE (GOT_TPREL16, REL) +RELOC_TYPE (GOT_TPREL16_LO, REL) +RELOC_TYPE (GOT_TPREL16_HI, REL) +RELOC_TYPE (GOT_TPREL16_HA, REL) +RELOC_TYPE (GOT_DTPREL16, REL) +RELOC_TYPE (GOT_DTPREL16_LO, REL) +RELOC_TYPE (GOT_DTPREL16_HI, REL) +RELOC_TYPE (GOT_DTPREL16_HA, REL) +RELOC_TYPE (EMB_NADDR32, REL) /* note 3 */ +RELOC_TYPE (EMB_NADDR16, REL) /* note 3 */ +RELOC_TYPE (EMB_NADDR16_LO, REL) /* note 3 */ +RELOC_TYPE (EMB_NADDR16_HI, REL) /* note 3 */ +RELOC_TYPE (EMB_NADDR16_HA, REL) /* note 3 */ +RELOC_TYPE (EMB_SDAI16, REL) /* note 3 */ +RELOC_TYPE (EMB_SDA2I16, REL) /* note 3 */ +RELOC_TYPE (EMB_SDA2REL, REL) /* note 3 */ +RELOC_TYPE (EMB_SDA21, REL) /* note 3 */ +RELOC_TYPE (EMB_MRKREF, REL) /* note 3 */ +RELOC_TYPE (EMB_RELSEC16, REL) /* note 3 */ +RELOC_TYPE (EMB_RELST_LO, REL) /* note 3 */ +RELOC_TYPE (EMB_RELST_HI, REL) /* note 3 */ +RELOC_TYPE (EMB_RELST_HA, REL) /* note 3 */ +RELOC_TYPE (EMB_BIT_FLD, REL) /* note 3 */ +RELOC_TYPE (EMB_RELSDA, REL) /* note 3 */ +RELOC_TYPE (DIAB_SDA21_LO, REL) /* note 3 */ +RELOC_TYPE (DIAB_SDA21_HI, REL) /* note 3 */ +RELOC_TYPE (DIAB_SDA21_HA, REL) /* note 3 */ +RELOC_TYPE (DIAB_RELSDA_LO, REL) /* note 3 */ +RELOC_TYPE (DIAB_RELSDA_HI, REL) /* note 3 */ +RELOC_TYPE (DIAB_RELSDA_HA, REL) /* note 3 */ +RELOC_TYPE (REL16, REL) /* note 2 */ +RELOC_TYPE (REL16_LO, REL) /* note 2 */ +RELOC_TYPE (REL16_HI, REL) /* note 2 */ +RELOC_TYPE (REL16_HA, REL) /* note 2 */ +RELOC_TYPE (TOC16, REL) /* note 2 */ + +/* Notes from Alan Modra: + + 1) These relocs should not really appear in EXEC or DYN, but they do, + primarily due to improper assembly or non-pic shared objects. They + will cause TEXTREL to be set. I marked them in the table, because + numerous people seem to think non-pic shared libs are a good idea. + + 2) As for (1), these relocs can appear anywhere with improper + assembler. I should probably make ld reject anything other than the + cases allowed in this table. Not seen in the wild, so I haven't + added the other cases. + + 3) Not used in SYSV4 +*/ diff --git a/backends/ppc_retval.c b/backends/ppc_retval.c new file mode 100644 index 00000000..b14a99f1 --- /dev/null +++ b/backends/ppc_retval.c @@ -0,0 +1,191 @@ +/* Function return value location for Linux/PPC ABI. + Copyright (C) 2005, 2006, 2007, 2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + + +/* This is the SVR4 ELF ABI convention, but AIX and Linux do not use it. */ +#define SVR4_STRUCT_RETURN 0 + + +/* r3, or pair r3, r4, or quad r3-r6. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg4 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg5 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg6 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 +#define nloc_intregquad 8 + +/* f1. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 33 } + }; +#define nloc_fpreg 1 + +/* vr2. */ +static const Dwarf_Op loc_vmxreg[] = + { + { .atom = DW_OP_regx, .number = 1124 + 2 } + }; +#define nloc_vmxreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r3. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg3, .number = 0 } + }; +#define nloc_aggregate 1 + + +/* XXX We should check the SHT_GNU_ATTRIBUTES bits here (or in ppc_init). */ +static bool +ppc_altivec_abi (void) +{ + return true; +} + +int +ppc_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + } + + if (size <= 8) + { + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, + DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + *locp = loc_fpreg; + return nloc_fpreg; + } + } + intreg: + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregpair; + } + + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_array_type: + { + Dwarf_Attribute attr_mem; + bool is_vector; + if (dwarf_formflag (dwarf_attr_integrate (typedie, DW_AT_GNU_vector, + &attr_mem), &is_vector) == 0 + && is_vector + && dwarf_aggregate_size (typedie, &size) == 0) + switch (size) + { + case 16: + if (ppc_altivec_abi ()) + { + *locp = loc_vmxreg; + return nloc_vmxreg; + } + *locp = loc_intreg; + return nloc_intregquad; + } + } + /* Fall through. */ + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + if (SVR4_STRUCT_RETURN + && dwarf_aggregate_size (typedie, &size) == 0 + && size > 0 && size <= 8) + goto intreg; + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/ppc_symbol.c b/backends/ppc_symbol.c new file mode 100644 index 00000000..c17ab374 --- /dev/null +++ b/backends/ppc_symbol.c @@ -0,0 +1,165 @@ +/* PPC specific symbolic name handling. + Copyright (C) 2004, 2005, 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2004. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <elf.h> +#include <stddef.h> +#include <string.h> + +#define BACKEND ppc_ +#include "libebl_CPU.h" + + +/* Check for the simple reloc types. */ +Elf_Type +ppc_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_PPC_ADDR32: + case R_PPC_UADDR32: + return ELF_T_WORD; + case R_PPC_UADDR16: + return ELF_T_HALF; + default: + return ELF_T_NUM; + } +} + + +const char * +ppc_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_PPC_GOT: + return "PPC_GOT"; + default: + break; + } + return NULL; +} + + +bool +ppc_dynamic_tag_check (int64_t tag) +{ + return tag == DT_PPC_GOT; +} + + +/* Look for DT_PPC_GOT. */ +static bool +find_dyn_got (Elf *elf, GElf_Addr *addr) +{ + size_t phnum; + if (elf_getphdrnum (elf, &phnum) != 0) + return false; + + for (size_t i = 0; i < phnum; ++i) + { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); + if (phdr == NULL || phdr->p_type != PT_DYNAMIC) + continue; + + Elf_Scn *scn = gelf_offscn (elf, phdr->p_offset); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + Elf_Data *data = elf_getdata (scn, NULL); + if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC && data != NULL) + for (unsigned int j = 0; j < shdr->sh_size / shdr->sh_entsize; ++j) + { + GElf_Dyn dyn_mem; + GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem); + if (dyn != NULL && dyn->d_tag == DT_PPC_GOT) + { + *addr = dyn->d_un.d_ptr; + return true; + } + } + + /* There is only one PT_DYNAMIC entry. */ + break; + } + + return false; +} + + +/* Check whether given symbol's st_value and st_size are OK despite failing + normal checks. */ +bool +ppc_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym, + const char *name, const GElf_Shdr *destshdr) +{ + if (name == NULL) + return false; + + if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + { + /* In -msecure-plt mode, DT_PPC_GOT is present and must match. */ + GElf_Addr gotaddr; + if (find_dyn_got (elf, &gotaddr)) + return sym->st_value == gotaddr; + + /* In -mbss-plt mode, any place in the section is valid. */ + return true; + } + + const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); + if (sname == NULL) + return false; + + if (strcmp (name, "_SDA_BASE_") == 0) + return (strcmp (sname, ".sdata") == 0 + && sym->st_value == destshdr->sh_addr + 0x8000 + && sym->st_size == 0); + + if (strcmp (name, "_SDA2_BASE_") == 0) + return (strcmp (sname, ".sdata2") == 0 + && sym->st_value == destshdr->sh_addr + 0x8000 + && sym->st_size == 0); + + return false; +} + + +/* Check if backend uses a bss PLT in this file. */ +bool +ppc_bss_plt_p (Elf *elf) +{ + GElf_Addr addr; + return ! find_dyn_got (elf, &addr); +} diff --git a/backends/ppc_syscall.c b/backends/ppc_syscall.c new file mode 100644 index 00000000..b1b9c52b --- /dev/null +++ b/backends/ppc_syscall.c @@ -0,0 +1,53 @@ +/* Linux/PPC system call ABI in DWARF register numbers. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +int +ppc_syscall_abi (Ebl *ebl __attribute__ ((unused)), + int *sp, int *pc, int *callno, int args[6]) +{ + *sp = 1; + *pc = -1; + *callno = 0; + args[0] = 3; + args[1] = 4; + args[2] = 5; + args[3] = 6; + args[4] = 7; + args[5] = 8; + return 0; +} + +__typeof (ppc_syscall_abi) +ppc64_syscall_abi __attribute__ ((alias ("ppc_syscall_abi"))); diff --git a/backends/s390_cfi.c b/backends/s390_cfi.c new file mode 100644 index 00000000..cb494861 --- /dev/null +++ b/backends/s390_cfi.c @@ -0,0 +1,65 @@ +/* s390 ABI-specified defaults for DWARF CFI. + Copyright (C) 2012, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + +int +s390_abi_cfi (Ebl *ebl, Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* This instruction is provided in every CIE. It is not repeated here: + DW_CFA_def_cfa, ULEB128_7 (15), ULEB128_7 (96) */ + /* r14 is not callee-saved but it needs to be preserved as it is pre-set + by the caller. */ + DW_CFA_same_value, ULEB128_7 (14), /* r14 */ + + /* Callee-saved regs. */ +#define SV(n) DW_CFA_same_value, ULEB128_7 (n) + SV (6), SV (7), SV (8), SV (9), SV (10), /* r6-r13, r15 */ + SV (11), SV (12), SV (13), SV (15), + SV (16 + 8), SV (16 + 9), SV (16 + 10), SV (16 + 11), /* f8-f15 */ + SV (16 + 12), SV (16 + 13), SV (16 + 14), SV (16 + 15) +#undef SV + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = ebl->class == ELFCLASS64 ? 8 : 4; + + abi_info->return_address_register = 14; + + return 0; +} diff --git a/backends/s390_corenote.c b/backends/s390_corenote.c new file mode 100644 index 00000000..7ca35168 --- /dev/null +++ b/backends/s390_corenote.c @@ -0,0 +1,189 @@ +/* S390-specific core note handling. + Copyright (C) 2012 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#ifndef BITS +# define BITS 32 +# define BACKEND s390_ +#else +# define BITS 64 +# define BACKEND s390x_ +#endif +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg, b...) \ + { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = b } + + GR ( 0, 1, 64, BITS), /* pswm */ + GR ( 1, 1, 65, BITS, .pc_register = true ), /* pswa */ + GR ( 2, 16, 0, BITS), /* r0-r15 */ + GR (18, 16, 48, 32), /* ar0-ar15 */ + +#undef GR + }; + + /* orig_r2 is at offset (BITS == 32 ? 34 * 4 : 26 * 8). */ +#define PRSTATUS_REGS_SIZE (BITS / 8 * (BITS == 32 ? 35 : 27)) + +static const Ebl_Register_Location fpregset_regs[] = + { +#define FPR(at, n, dwreg) \ + { .offset = at * 64/8, .regno = dwreg, .count = n, .bits = 64 } + + /* fpc is at offset 0, see fpregset_items, it has no assigned DWARF regno. + Bytes at offsets 4 to 7 are unused. */ + FPR (1 + 0, 1, 16), /* f0 */ + FPR (1 + 1, 1, 20), /* f1 */ + FPR (1 + 2, 1, 17), /* f2 */ + FPR (1 + 3, 1, 21), /* f3 */ + FPR (1 + 4, 1, 18), /* f4 */ + FPR (1 + 5, 1, 22), /* f5 */ + FPR (1 + 6, 1, 19), /* f6 */ + FPR (1 + 7, 1, 23), /* f7 */ + FPR (1 + 8, 1, 24), /* f8 */ + FPR (1 + 9, 1, 28), /* f9 */ + FPR (1 + 10, 1, 25), /* f10 */ + FPR (1 + 11, 1, 29), /* f11 */ + FPR (1 + 12, 1, 26), /* f12 */ + FPR (1 + 13, 1, 30), /* f13 */ + FPR (1 + 14, 1, 27), /* f14 */ + FPR (1 + 15, 1, 31), /* f15 */ + +#undef FPR + }; + +static const Ebl_Core_Item fpregset_items[] = + { + { + .name = "fpc", .group = "register", .offset = 0, .type = ELF_T_WORD, + .format = 'x', + }, + }; + +/* Do not set FPREGSET_SIZE so that we can supply fpregset_items. */ +#define EXTRA_NOTES_FPREGSET \ + EXTRA_REGSET_ITEMS (NT_FPREGSET, 17 * 8, fpregset_regs, fpregset_items) + +#if BITS == 32 +# define ULONG uint32_t +# define ALIGN_ULONG 4 +# define TYPE_ULONG ELF_T_WORD +# define TYPE_LONG ELF_T_SWORD +# define UID_T uint16_t +# define GID_T uint16_t +# define ALIGN_UID_T 2 +# define ALIGN_GID_T 2 +# define TYPE_UID_T ELF_T_HALF +# define TYPE_GID_T ELF_T_HALF +#else +# define ULONG uint64_t +# define ALIGN_ULONG 8 +# define TYPE_ULONG ELF_T_XWORD +# define TYPE_LONG ELF_T_SXWORD +# define UID_T uint32_t +# define GID_T uint32_t +# define ALIGN_UID_T 4 +# define ALIGN_GID_T 4 +# define TYPE_UID_T ELF_T_WORD +# define TYPE_GID_T ELF_T_WORD +#endif +#define PID_T int32_t +#define ALIGN_PID_T 4 +#define TYPE_PID_T ELF_T_SWORD +/* s390 psw_compat_t has alignment 8 bytes where it is inherited from. */ +#define ALIGN_PR_REG 8 + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_r2", .type = TYPE_LONG, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), \ + pr_reg[BITS == 32 ? 34 : 26]), \ + .group = "register" \ + } + +#if BITS == 32 + +static const Ebl_Core_Item high_regs_items[] = + { +#define HR(n) \ + { \ + .name = "high_r" #n , .group = "register", .offset = (n) * 4, \ + .type = ELF_T_WORD, .format = 'x', \ + } + + /* Upper halves of r0-r15 are stored here. + FIXME: They are currently not combined with the r0-r15 lower halves. */ + HR (0), HR (1), HR (2), HR (3), HR (4), HR (5), HR (6), HR (7), + HR (8), HR (9), HR (10), HR (11), HR (12), HR (13), HR (14), HR (15) + +#undef HR + }; + +#define EXTRA_NOTES_HIGH_GPRS \ + EXTRA_ITEMS (NT_S390_HIGH_GPRS, 16 * 4, high_regs_items) + +#else /* BITS == 64 */ + +#define EXTRA_NOTES_HIGH_GPRS + +#endif /* BITS == 64 */ + +static const Ebl_Core_Item last_break_items[] = + { + { + .name = "last_break", .group = "system", .offset = BITS == 32 ? 4 : 0, + .type = BITS == 32 ? ELF_T_WORD : ELF_T_XWORD, .format = 'x', + }, + }; + +static const Ebl_Core_Item system_call_items[] = + { + { + .name = "system_call", .group = "system", .offset = 0, .type = ELF_T_WORD, + .format = 'd', + }, + }; + +#define EXTRA_NOTES \ + EXTRA_NOTES_FPREGSET \ + EXTRA_NOTES_HIGH_GPRS \ + EXTRA_ITEMS (NT_S390_LAST_BREAK, 8, last_break_items) \ + EXTRA_ITEMS (NT_S390_SYSTEM_CALL, 4, system_call_items) + +#include "linux-core-note.c" diff --git a/backends/s390_init.c b/backends/s390_init.c new file mode 100644 index 00000000..26b20b49 --- /dev/null +++ b/backends/s390_init.c @@ -0,0 +1,80 @@ +/* Initialization of S/390 specific backend library. + Copyright (C) 2005, 2006, 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND s390_ +#define RELOC_PREFIX R_390_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on arm_reloc.def. */ +#include "common-reloc.c" + +extern __typeof (s390_core_note) s390x_core_note; + + +const char * +s390_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "IBM S/390"; + s390_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + if (eh->class == ELFCLASS64) + eh->core_note = s390x_core_note; + else + HOOK (eh, core_note); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS 34. + But from the gcc/config/s390/s390.h "Register usage." comment it looks as + if #32 (Argument pointer) and #33 (Condition code) are not used for + unwinding. */ + eh->frame_nregs = 32; + HOOK (eh, set_initial_registers_tid); + if (eh->class == ELFCLASS32) + HOOK (eh, normalize_pc); + HOOK (eh, unwind); + + /* Only the 64-bit format uses the incorrect hash table entry size. */ + if (eh->class == ELFCLASS64) + eh->sysvhash_entrysize = sizeof (Elf64_Xword); + + return MODVERSION; +} diff --git a/backends/s390_initreg.c b/backends/s390_initreg.c new file mode 100644 index 00000000..b4c4b67c --- /dev/null +++ b/backends/s390_initreg.c @@ -0,0 +1,95 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "system.h" +#include <assert.h> +#ifdef __s390__ +# include <sys/user.h> +# include <asm/ptrace.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND s390_ +#include "libebl_CPU.h" + +bool +s390_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#ifndef __s390__ + return false; +#else /* __s390__ */ + struct user user_regs; + ptrace_area parea; + parea.process_addr = (uintptr_t) &user_regs; + parea.kernel_addr = 0; + parea.len = sizeof (user_regs); + if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea, NULL) != 0) + return false; + /* If we run as s390x we get the 64-bit registers of tid. + But -m31 executable seems to use only the 32-bit parts of its + registers so we ignore the upper half. */ + Dwarf_Word dwarf_regs[16]; + for (unsigned u = 0; u < 16; u++) + dwarf_regs[u] = user_regs.regs.gprs[u]; + if (! setfunc (0, 16, dwarf_regs, arg)) + return false; + /* Avoid conversion double -> integer. */ + eu_static_assert (sizeof user_regs.regs.fp_regs.fprs[0] + == sizeof dwarf_regs[0]); + for (unsigned u = 0; u < 16; u++) + { + // Store the double bits as is in the Dwarf_Word without conversion. + union + { + double d; + Dwarf_Word w; + } fpr = { .d = user_regs.regs.fp_regs.fprs[u] }; + dwarf_regs[u] = fpr.w; + } + + if (! setfunc (16, 16, dwarf_regs, arg)) + return false; + dwarf_regs[0] = user_regs.regs.psw.addr; + return setfunc (-1, 1, dwarf_regs, arg); +#endif /* __s390__ */ +} + +void +s390_normalize_pc (Ebl *ebl __attribute__ ((unused)), Dwarf_Addr *pc) +{ + assert (ebl->class == ELFCLASS32); + + /* Clear S390 bit 31. */ + *pc &= (1U << 31) - 1; +} diff --git a/backends/s390_regs.c b/backends/s390_regs.c new file mode 100644 index 00000000..ba6178a3 --- /dev/null +++ b/backends/s390_regs.c @@ -0,0 +1,146 @@ +/* Register names and numbers for S/390 DWARF. + Copyright (C) 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + + +/* +zseries (64) + +0-15 gpr0-gpr15 x +16-19 fpr[0246] +20-24 fpr[13578] +25-27 fpr1[024] +28 fpr9 +29-31 fpr1[135] +32-47 cr0-cr15 x +48-63 ar0-ar15 x +64 psw_mask +65 psw_address +*/ + + +ssize_t +s390_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 66; + + if (regno < 0 || regno > 65 || namelen < 7) + return -1; + + *prefix = "%"; + + *bits = ebl->class == ELFCLASS64 ? 64 : 32; + *type = DW_ATE_unsigned; + if (regno < 16) + { + *setname = "integer"; + *type = DW_ATE_signed; + } + else if (regno < 32) + { + *setname = "FPU"; + *type = DW_ATE_float; + *bits = 64; + } + else if (regno < 48 || regno > 63) + *setname = "control"; + else + { + *setname = "access"; + *bits = 32; + } + + switch (regno) + { + case 0 ... 9: + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 15: + name[0] = 'r'; + name[1] = '1'; + name[2] = regno - 10 + '0'; + namelen = 3; + break; + + case 16 ... 31: + name[0] = 'f'; + regno = (regno & 8) | ((regno & 4) >> 2) | ((regno & 3) << 1); + namelen = 1; + if (regno >= 10) + { + regno -= 10; + name[namelen++] = '1'; + } + name[namelen++] = regno + '0'; + break; + + case 32 + 0 ... 32 + 9: + case 48 + 0 ... 48 + 9: + name[0] = regno < 48 ? 'c' : 'a'; + name[1] = (regno & 15) + '0'; + namelen = 2; + break; + + case 32 + 10 ... 32 + 15: + case 48 + 10 ... 48 + 15: + name[0] = regno < 48 ? 'c' : 'a'; + name[1] = '1'; + name[2] = (regno & 15) - 10 + '0'; + namelen = 3; + break; + + case 64: + return stpcpy (name, "pswm") + 1 - name; + case 65: + *type = DW_ATE_address; + return stpcpy (name, "pswa") + 1 - name; + + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/s390_reloc.def b/backends/s390_reloc.def new file mode 100644 index 00000000..b4686a30 --- /dev/null +++ b/backends/s390_reloc.def @@ -0,0 +1,91 @@ +/* List the relocation types for s390. -*- C -*- + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (8, REL|EXEC|DYN) +RELOC_TYPE (12, REL|EXEC|DYN) +RELOC_TYPE (16, REL|EXEC|DYN) +RELOC_TYPE (32, REL|EXEC|DYN) +RELOC_TYPE (PC32, REL|EXEC|DYN) +RELOC_TYPE (GOT12, REL) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTOFF32, REL) +RELOC_TYPE (GOTPC, REL) +RELOC_TYPE (GOT16, REL) +RELOC_TYPE (PC16, REL|EXEC|DYN) +RELOC_TYPE (PC16DBL, REL|EXEC|DYN) +RELOC_TYPE (PLT16DBL, REL) +RELOC_TYPE (PC32DBL, REL|EXEC|DYN) +RELOC_TYPE (PLT32DBL, REL) +RELOC_TYPE (GOTPCDBL, REL) +RELOC_TYPE (64, REL|EXEC|DYN) +RELOC_TYPE (PC64, REL|EXEC|DYN) +RELOC_TYPE (GOT64, REL) +RELOC_TYPE (PLT64, REL) +RELOC_TYPE (GOTENT, REL) +RELOC_TYPE (GOTOFF16, REL) +RELOC_TYPE (GOTOFF64, REL) +RELOC_TYPE (GOTPLT12, REL) +RELOC_TYPE (GOTPLT16, REL) +RELOC_TYPE (GOTPLT32, REL) +RELOC_TYPE (GOTPLT64, REL) +RELOC_TYPE (GOTPLTENT, REL) +RELOC_TYPE (PLTOFF16, REL) +RELOC_TYPE (PLTOFF32, REL) +RELOC_TYPE (PLTOFF64, REL) +RELOC_TYPE (TLS_LOAD, REL) +RELOC_TYPE (TLS_GDCALL, REL) +RELOC_TYPE (TLS_LDCALL, REL) +RELOC_TYPE (TLS_GD32, REL) +RELOC_TYPE (TLS_GD64, REL) +RELOC_TYPE (TLS_GOTIE12, REL) +RELOC_TYPE (TLS_GOTIE32, REL) +RELOC_TYPE (TLS_GOTIE64, REL) +RELOC_TYPE (TLS_LDM32, REL) +RELOC_TYPE (TLS_LDM64, REL) +RELOC_TYPE (TLS_IE32, REL) +RELOC_TYPE (TLS_IE64, REL) +RELOC_TYPE (TLS_IEENT, REL) +RELOC_TYPE (TLS_LE32, REL) +RELOC_TYPE (TLS_LE64, REL) +RELOC_TYPE (TLS_LDO32, REL) +RELOC_TYPE (TLS_LDO64, REL) +RELOC_TYPE (TLS_DTPMOD, DYN) +RELOC_TYPE (TLS_DTPOFF, DYN) +RELOC_TYPE (TLS_TPOFF, DYN) +RELOC_TYPE (20, REL|EXEC|DYN) +RELOC_TYPE (GOT20, REL) +RELOC_TYPE (GOTPLT20, REL) +RELOC_TYPE (TLS_GOTIE20, REL) diff --git a/backends/s390_retval.c b/backends/s390_retval.c new file mode 100644 index 00000000..a927d46a --- /dev/null +++ b/backends/s390_retval.c @@ -0,0 +1,144 @@ +/* Function return value location for S/390 ABI. + Copyright (C) 2006, 2007, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + + +/* %r2, or pair %r2, %r3. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg2 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg3 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %f0. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_reg16 }, + }; +#define nloc_fpreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %r2. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg2, .number = 0 } + }; +#define nloc_aggregate 1 + + +int +s390_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Die cudie; + uint8_t asize; + if (dwarf_diecu (typedie, &cudie, &asize, NULL) == NULL) + return -1; + + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = asize; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float && size <= 8) + { + *locp = loc_fpreg; + return nloc_fpreg; + } + } + if (size <= 8) + { + *locp = loc_intreg; + return size <= asize ? nloc_intreg : nloc_intregpair; + } + } + /* Fall through. */ + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + *locp = loc_aggregate; + return nloc_aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/s390_symbol.c b/backends/s390_symbol.c new file mode 100644 index 00000000..a0a4fafa --- /dev/null +++ b/backends/s390_symbol.c @@ -0,0 +1,56 @@ +/* S/390-specific symbolic name handling. + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + +/* Check for the simple reloc types. */ +Elf_Type +s390_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_390_64: + return ELF_T_SXWORD; + case R_390_32: + return ELF_T_SWORD; + case R_390_16: + return ELF_T_HALF; + case R_390_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} diff --git a/backends/s390_unwind.c b/backends/s390_unwind.c new file mode 100644 index 00000000..752bc287 --- /dev/null +++ b/backends/s390_unwind.c @@ -0,0 +1,139 @@ +/* Get previous frame state for an existing frame state. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <assert.h> + +#define BACKEND s390_ +#include "libebl_CPU.h" + +/* s390/s390x do not annotate signal handler frame by CFI. It would be also + difficult as PC points into a stub built on stack. Function below is called + only if unwinder could not find CFI. Function then verifies the register + state for this frame really belongs to a signal frame. In such case it + fetches original registers saved by the signal frame. */ + +bool +s390_unwind (Ebl *ebl, Dwarf_Addr pc, ebl_tid_registers_t *setfunc, + ebl_tid_registers_get_t *getfunc, ebl_pid_memory_read_t *readfunc, + void *arg, bool *signal_framep) +{ + /* Caller already assumed caller adjustment but S390 instructions are 4 bytes + long. Undo it. */ + if ((pc & 0x3) != 0x3) + return false; + pc++; + /* We can assume big-endian read here. */ + Dwarf_Word instr; + if (! readfunc (pc, &instr, arg)) + return false; + /* Fetch only the very first two bytes. */ + instr = (instr >> (ebl->class == ELFCLASS64 ? 48 : 16)) & 0xffff; + /* See GDB s390_sigtramp_frame_sniffer. */ + /* Check for 'svc' as the first instruction. */ + if (((instr >> 8) & 0xff) != 0x0a) + return false; + /* Check for 'sigreturn' or 'rt_sigreturn' as the second instruction. */ + if ((instr & 0xff) != 119 && (instr & 0xff) != 173) + return false; + /* See GDB s390_sigtramp_frame_unwind_cache. */ + Dwarf_Word this_sp; + if (! getfunc (0 + 15, 1, &this_sp, arg)) + return false; + unsigned word_size = ebl->class == ELFCLASS64 ? 8 : 4; + Dwarf_Addr next_cfa = this_sp + 16 * word_size + 32; + /* "New-style RT frame" is not supported, + assuming "Old-style RT frame and all non-RT frames". + Pointer to the array of saved registers is at NEXT_CFA + 8. */ + Dwarf_Word sigreg_ptr; + if (! readfunc (next_cfa + 8, &sigreg_ptr, arg)) + return false; + /* Skip PSW mask. */ + sigreg_ptr += word_size; + /* Read PSW address. */ + Dwarf_Word val; + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + if (! setfunc (-1, 1, &val, arg)) + return false; + sigreg_ptr += word_size; + /* Then the GPRs. */ + Dwarf_Word gprs[16]; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &gprs[i], arg)) + return false; + sigreg_ptr += word_size; + } + /* Then the ACRs. Skip them, they are not used in CFI. */ + for (int i = 0; i < 16; i++) + sigreg_ptr += 4; + /* The floating-point control word. */ + sigreg_ptr += 8; + /* And finally the FPRs. */ + Dwarf_Word fprs[16]; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + if (ebl->class == ELFCLASS32) + { + Dwarf_Addr val_low; + if (! readfunc (sigreg_ptr + 4, &val_low, arg)) + return false; + val = (val << 32) | val_low; + } + fprs[i] = val; + sigreg_ptr += 8; + } + /* If we have them, the GPR upper halves are appended at the end. */ + if (ebl->class == ELFCLASS32) + { + /* Skip signal number. */ + sigreg_ptr += 4; + for (int i = 0; i < 16; i++) + { + if (! readfunc (sigreg_ptr, &val, arg)) + return false; + Dwarf_Word val_low = gprs[i]; + val = (val << 32) | val_low; + gprs[i] = val; + sigreg_ptr += 4; + } + } + if (! setfunc (0, 16, gprs, arg)) + return false; + if (! setfunc (16, 16, fprs, arg)) + return false; + *signal_framep = true; + return true; +} diff --git a/backends/s390x_corenote.c b/backends/s390x_corenote.c new file mode 100644 index 00000000..427bf7de --- /dev/null +++ b/backends/s390x_corenote.c @@ -0,0 +1,2 @@ +#define BITS 64 +#include "s390_corenote.c" diff --git a/backends/sh_corenote.c b/backends/sh_corenote.c new file mode 100644 index 00000000..9268f568 --- /dev/null +++ b/backends/sh_corenote.c @@ -0,0 +1,88 @@ +/* SH specific core note handling. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + Contributed Matt Fleming <matt@console-pimps.org>. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND sh_ +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * 4, .regno = dwreg, .count = n, .bits = 32 } + GR (0, 16, 0), /* r0-r15 */ + GR (16, 1, 16), /* pc */ + GR (17, 1, 17), /* pr */ + GR (18, 1, 22), /* sr */ + GR (19, 1, 18), /* gbr */ + GR (20, 1, 20), /* mach */ + GR (21, 1, 21), /* macl */ + /* 22, 1, tra */ +#undef GR + }; +#define PRSTATUS_REGS_SIZE (23 * 4) + +#define ULONG uint32_t +#define PID_T int32_t +#define UID_T uint16_t +#define GID_T uint16_t +#define ALIGN_ULONG 4 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 2 +#define ALIGN_GID_T 2 +#define TYPE_ULONG ELF_T_WORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_HALF +#define TYPE_GID_T ELF_T_HALF + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "tra", .type = ELF_T_ADDR, .format = 'x', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg[22]), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 25, .count = 16, .bits = 32 }, /* fr0-fr15 */ + { .offset = 16, .regno = 87, .count = 16, .bits = 32 }, /* xf0-xf15 */ + { .offset = 32, .regno = 24, .count = 1, .bits = 32 }, /* fpscr */ + { .offset = 33, .regno = 23, .count = 1, .bits = 32 } /* fpul */ + }; +#define FPREGSET_SIZE (50 * 4) + +#include "linux-core-note.c" diff --git a/backends/sh_init.c b/backends/sh_init.c new file mode 100644 index 00000000..90ddcb2c --- /dev/null +++ b/backends/sh_init.c @@ -0,0 +1,64 @@ +/* Initialization of SH specific backend library. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND sh_ +#define RELOC_PREFIX R_SH_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on sh_reloc.def. */ +#include "common-reloc.c" + + +const char * +sh_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "Hitachi SH"; + sh_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, gotpc_reloc_check); + HOOK (eh, machine_flag_check); + HOOK (eh, core_note); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + + return MODVERSION; +} diff --git a/backends/sh_regs.c b/backends/sh_regs.c new file mode 100644 index 00000000..d4332364 --- /dev/null +++ b/backends/sh_regs.c @@ -0,0 +1,191 @@ +/* Register names and numbers for SH DWARF. + Copyright (C) 2010 Red Hat, Inc. + This file is part of elfutils. + Contributed by Matt Fleming <matt@console-pimps.org>. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include <string.h> + +#define BACKEND sh_ +#include "libebl_CPU.h" + +ssize_t +sh_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 104; + + if (regno < 0 || regno > 103 || namelen < 6) + return -1; + + *prefix = ""; + *bits = 32; + *type = DW_ATE_signed; + + switch (regno) + { + case 0 ... 9: + *setname = "integer"; + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 15: + *setname = "integer"; + name[0] = 'r'; + name[1] = '1'; + name[2] = regno - 10 + '0'; + namelen = 3; + break; + + case 16: + *setname = "system"; + *type = DW_ATE_address; + name[0] = 'p'; + name[1] = 'c'; + namelen = 2; + break; + + case 17: + *setname = "system"; + *type = DW_ATE_address; + name[0] = 'p'; + name[1] = 'r'; + namelen = 2; + break; + + case 18: + *setname = "control"; + *type = DW_ATE_unsigned; + name[0] = 's'; + name[1] = 'r'; + namelen = 2; + break; + + case 19: + *setname = "control"; + *type = DW_ATE_unsigned; + name[0] = 'g'; + name[1] = 'b'; + name[2] = 'r'; + namelen = 3; + break; + + case 20: + *setname = "system"; + name[0] = 'm'; + name[1] = 'a'; + name[2] = 'c'; + name[3] = 'h'; + namelen = 4; + break; + + case 21: + *setname = "system"; + name[0] = 'm'; + name[1] = 'a'; + name[2] = 'c'; + name[3] = 'l'; + namelen = 4; + + break; + + case 23: + *setname = "system"; + *type = DW_ATE_unsigned; + name[0] = 'f'; + name[1] = 'p'; + name[2] = 'u'; + name[3] = 'l'; + namelen = 4; + break; + + case 24: + *setname = "system"; + *type = DW_ATE_unsigned; + name[0] = 'f'; + name[1] = 'p'; + name[2] = 's'; + name[3] = 'c'; + name[4] = 'r'; + namelen = 5; + break; + + case 25 ... 34: + *setname = "fpu"; + *type = DW_ATE_float; + name[0] = 'f'; + name[1] = 'r'; + name[2] = regno - 25 + '0'; + namelen = 3; + break; + + case 35 ... 40: + *setname = "fpu"; + *type = DW_ATE_float; + name[0] = 'f'; + name[1] = 'r'; + name[2] = '1'; + name[3] = regno - 35 + '0'; + namelen = 4; + break; + + case 87 ... 96: + *type = DW_ATE_float; + *setname = "fpu"; + name[0] = 'x'; + name[1] = 'f'; + name[2] = regno - 87 + '0'; + namelen = 3; + break; + + case 97 ... 103: + *type = DW_ATE_float; + *setname = "fpu"; + name[0] = 'x'; + name[1] = 'f'; + name[2] = '1'; + name[3] = regno - 97 + '0'; + namelen = 4; + break; + + default: + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/sh_reloc.def b/backends/sh_reloc.def new file mode 100644 index 00000000..66a5a9d2 --- /dev/null +++ b/backends/sh_reloc.def @@ -0,0 +1,67 @@ +/* List the relocation types for SH. -*- C -*- + Copyright (C) 2005 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (DIR32, REL|DYN) +RELOC_TYPE (REL32, REL|DYN) +RELOC_TYPE (DIR8WPN, REL) +RELOC_TYPE (IND12W, REL) +RELOC_TYPE (DIR8WPL, REL) +RELOC_TYPE (DIR8WPZ, REL) +RELOC_TYPE (DIR8BP, REL) +RELOC_TYPE (DIR8W, REL) +RELOC_TYPE (DIR8L, REL) +RELOC_TYPE (SWITCH16, REL) +RELOC_TYPE (SWITCH32, REL) +RELOC_TYPE (USES, REL) +RELOC_TYPE (COUNT, REL) +RELOC_TYPE (ALIGN, REL) +RELOC_TYPE (CODE, REL) +RELOC_TYPE (DATA, REL) +RELOC_TYPE (LABEL, REL) +RELOC_TYPE (SWITCH8, REL) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (GNU_VTENTRY, REL) +RELOC_TYPE (TLS_GD_32, REL) +RELOC_TYPE (TLS_LD_32, REL) +RELOC_TYPE (TLS_LDO_32, REL) +RELOC_TYPE (TLS_IE_32, REL) +RELOC_TYPE (TLS_LE_32, REL) +RELOC_TYPE (TLS_DTPMOD32, DYN) +RELOC_TYPE (TLS_DTPOFF32, DYN) +RELOC_TYPE (TLS_TPOFF32, DYN) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTOFF, REL) +RELOC_TYPE (GOTPC, REL) diff --git a/backends/sh_retval.c b/backends/sh_retval.c new file mode 100644 index 00000000..d44f2601 --- /dev/null +++ b/backends/sh_retval.c @@ -0,0 +1,131 @@ +/* Function return value location for Linux/SH ABI. + Copyright (C) 2010, 2014 Red Hat, Inc. + This file is part of elfutils. + Contributed by Matt Fleming <matt@console-pimps.org>. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND sh_ +#include "libebl_CPU.h" + + +/* This is the SVR4 ELF ABI convention, but AIX and Linux do not use it. */ +#define SVR4_STRUCT_RETURN 0 + + +/* r0, or pair r0, r1. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* fr0 or fr1. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_reg25 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg26 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_fpreg 1 +#define nloc_fpregpair 2 + +int +sh_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 4; + else + return -1; + } + } + + if (size <= 8) + { + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, + DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + *locp = loc_fpreg; + return size <= 4 ? nloc_fpreg : nloc_fpregpair; + } + } + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregpair; + } + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/sh_symbol.c b/backends/sh_symbol.c new file mode 100644 index 00000000..8101e96f --- /dev/null +++ b/backends/sh_symbol.c @@ -0,0 +1,94 @@ +/* SH specific relocation handling. + Copyright (C) 2000, 2001, 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND sh_ +#include "libebl_CPU.h" + + +/* Return true if the symbol type is that referencing the GOT. */ +bool +sh_gotpc_reloc_check (Elf *elf __attribute__ ((unused)), int type) +{ + return type == R_SH_GOTPC; +} + +/* Check for the simple reloc types. */ +Elf_Type +sh_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_SH_DIR32: + return ELF_T_WORD; + default: + return ELF_T_NUM; + } +} + +/* Check whether machine flags are valid. */ +bool +sh_machine_flag_check (GElf_Word flags) +{ + switch (flags & EF_SH_MACH_MASK) + { + case EF_SH_UNKNOWN: + case EF_SH1: + case EF_SH2: + case EF_SH3: + case EF_SH_DSP: + case EF_SH3_DSP: + case EF_SH4AL_DSP: + case EF_SH3E: + case EF_SH4: + case EF_SH2E: + case EF_SH4A: + case EF_SH2A: + case EF_SH4_NOFPU: + case EF_SH4A_NOFPU: + case EF_SH4_NOMMU_NOFPU: + case EF_SH2A_NOFPU: + case EF_SH3_NOMMU: + case EF_SH2A_SH4_NOFPU: + case EF_SH2A_SH3_NOFPU: + case EF_SH2A_SH4: + case EF_SH2A_SH3E: + break; + default: + return false; + } + + return ((flags &~ (EF_SH_MACH_MASK)) == 0); +} diff --git a/backends/sparc64_corenote.c b/backends/sparc64_corenote.c new file mode 100644 index 00000000..cef6431e --- /dev/null +++ b/backends/sparc64_corenote.c @@ -0,0 +1,2 @@ +#define BITS 64 +#include "sparc_corenote.c" diff --git a/backends/sparc_auxv.c b/backends/sparc_auxv.c new file mode 100644 index 00000000..2da349ca --- /dev/null +++ b/backends/sparc_auxv.c @@ -0,0 +1,46 @@ +/* SPARC-specific auxv handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND sparc_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "flush\0" "stbar\0" "swap\0" "muldiv\0" "v9\0" "ultra3\0" "v9v\0" "\0"; + return 1; +} diff --git a/backends/sparc_corenote.c b/backends/sparc_corenote.c new file mode 100644 index 00000000..7912539b --- /dev/null +++ b/backends/sparc_corenote.c @@ -0,0 +1,112 @@ +/* PowerPC specific core note handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#ifndef BITS +# define BITS 32 +# define BACKEND sparc_ +#else +# define BITS 64 +# define BACKEND sparc64_ +#endif +#include "libebl_CPU.h" + +#define GR(at, n, dwreg) \ + { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = BITS } + +static const Ebl_Register_Location prstatus_regs[] = + { + GR (0, 32, 0), /* %g0-%g7, %o0-%o7, %i0-%i7 */ +#if BITS == 32 + GR (32, 1, 65), /* %psr */ + GR (33, 2, 68), /* %pc, %npc */ + GR (35, 1, 64), /* %y */ + GR (36, 1, 66), /* %wim, %tbr */ +#else + GR (32, 1, 82), /* %state */ + GR (33, 2, 80), /* %pc, %npc */ + GR (35, 1, 85), /* %y */ +#endif + }; +#define PRSTATUS_REGS_SIZE (BITS / 8 * (32 + (BITS == 32 ? 6 : 4))) + +static const Ebl_Register_Location fpregset_regs[] = + { +#if BITS == 32 + GR (0, 32, 32), /* %f0-%f31 */ + /* padding word */ + GR (33, 1, 70), /* %fsr */ + /* qcnt, q_entrysize, en, q, padding */ +# define FPREGSET_SIZE (34 * 4 + 4 + 64 * 4 + 4) +#else + GR (0, 32, 32), /* %f0-%f31 */ + GR (32, 1, 83), /* %fsr */ + /* 33, 1, %gsr */ + GR (34, 1, 84), /* %fprs */ +# define FPREGSET_SIZE (35 * 8) +#endif + }; + +#if BITS == 32 +# define ULONG uint32_t +# define ALIGN_ULONG 4 +# define TYPE_ULONG ELF_T_WORD +# define TYPE_LONG ELF_T_SWORD +# define UID_T uint16_t +# define GID_T uint16_t +# define ALIGN_UID_T 2 +# define ALIGN_GID_T 2 +# define TYPE_UID_T ELF_T_HALF +# define TYPE_GID_T ELF_T_HALF +#else +# define ULONG uint64_t +# define ALIGN_ULONG 8 +# define TYPE_ULONG ELF_T_XWORD +# define TYPE_LONG ELF_T_SXWORD +# define UID_T uint32_t +# define GID_T uint32_t +# define ALIGN_UID_T 4 +# define ALIGN_GID_T 4 +# define TYPE_UID_T ELF_T_WORD +# define TYPE_GID_T ELF_T_WORD +# define SUSECONDS_HALF 1 +#endif +#define PID_T int32_t +#define ALIGN_PID_T 4 +#define TYPE_PID_T ELF_T_SWORD + +#include "linux-core-note.c" diff --git a/backends/sparc_init.c b/backends/sparc_init.c new file mode 100644 index 00000000..7d229981 --- /dev/null +++ b/backends/sparc_init.c @@ -0,0 +1,76 @@ +/* Initialization of SPARC specific backend library. + Copyright (C) 2002, 2005, 2006, 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND sparc_ +#define RELOC_PREFIX R_SPARC_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on sparc_reloc.def. */ +#include "common-reloc.c" + +extern __typeof (EBLHOOK (core_note)) sparc64_core_note attribute_hidden; + +const char * +sparc_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + if (machine == EM_SPARCV9) + eh->name = "SPARC v9"; + else if (machine == EM_SPARC32PLUS) + eh->name = "SPARC v8+"; + else + eh->name = "SPARC"; + sparc_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, machine_flag_check); + HOOK (eh, check_special_section); + HOOK (eh, symbol_type_name); + HOOK (eh, dynamic_tag_name); + HOOK (eh, dynamic_tag_check); + if (eh->class == ELFCLASS64) + eh->core_note = sparc64_core_note; + else + HOOK (eh, core_note); + HOOK (eh, auxv_info); + HOOK (eh, register_info); + HOOK (eh, return_value_location); + + return MODVERSION; +} diff --git a/backends/sparc_regs.c b/backends/sparc_regs.c new file mode 100644 index 00000000..f9709bb3 --- /dev/null +++ b/backends/sparc_regs.c @@ -0,0 +1,111 @@ +/* Register names and numbers for SPARC DWARF. + Copyright (C) 2005, 2006 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> +#include <dwarf.h> + +#define BACKEND sparc_ +#include "libebl_CPU.h" + +ssize_t +sparc_register_info (Ebl *ebl, + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + const int nfp = 32 + (ebl->machine == EM_SPARC ? 0 : 16); + const int nspec = ebl->machine == EM_SPARC ? 8 : 6; + + if (name == NULL) + return 32 + nfp + nspec; + + if (regno < 0 || regno >= 32 + nfp + nspec || namelen < 6) + return -1; + + *bits = ebl->machine == EM_SPARC ? 32 : 64; + *type = DW_ATE_signed; + + *prefix = "%"; + + if (regno >= 32 + nfp) + { + regno -= 32 + nfp; + static const char names[2][8][6] = + { + { "y", "psr", "wim", "tbr", "pc", "npc", "fsr", "csr" }, /* v8 */ + { "pc", "npc", "state", "fsr", "fprs", "y" } /* v9 */ + }; + *setname = "control"; + *type = DW_ATE_unsigned; + if ((ebl->machine != EM_SPARC ? 0 : 4) + 1 - (unsigned int) regno <= 1) + *type = DW_ATE_address; + return stpncpy (name, names[ebl->machine != EM_SPARC][regno], + namelen) + 1 - name; + } + + if (regno < 32) + { + *setname = "integer"; + name[0] = "goli"[regno >> 3]; + name[1] = (regno & 7) + '0'; + namelen = 2; + if ((regno & 8) && (regno & 7) == 6) + *type = DW_ATE_address; + } + else + { + *setname = "FPU"; + *type = DW_ATE_float; + + regno -= 32; + if (regno >= 32) + regno = 32 + 2 * (regno - 32); + else + *bits = 32; + + name[0] = 'f'; + if (regno < 10) + { + name[1] = regno + '0'; + namelen = 2; + } + else + { + name[1] = regno / 10 + '0'; + name[2] = regno % 10 + '0'; + namelen = 3; + } + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/sparc_reloc.def b/backends/sparc_reloc.def new file mode 100644 index 00000000..c39b0fae --- /dev/null +++ b/backends/sparc_reloc.def @@ -0,0 +1,121 @@ +/* List the relocation types for sparc. -*- C -*- + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, REL) +RELOC_TYPE (8, REL) +RELOC_TYPE (16, REL) +RELOC_TYPE (32, REL|DYN) +RELOC_TYPE (DISP8, REL) +RELOC_TYPE (DISP16, REL) +RELOC_TYPE (DISP32, REL) +RELOC_TYPE (WDISP30, REL) +RELOC_TYPE (WDISP22, REL) +RELOC_TYPE (HI22, REL) +RELOC_TYPE (22, REL) +RELOC_TYPE (13, REL) +RELOC_TYPE (LO10, REL) +RELOC_TYPE (GOT10, REL) +RELOC_TYPE (GOT13, REL) +RELOC_TYPE (GOT22, REL) +RELOC_TYPE (PC10, REL) +RELOC_TYPE (PC22, REL) +RELOC_TYPE (WPLT30, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (UA32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (HIPLT22, REL) +RELOC_TYPE (LOPLT10, REL) +RELOC_TYPE (PCPLT32, REL) +RELOC_TYPE (PCPLT22, REL) +RELOC_TYPE (PCPLT10, REL) +RELOC_TYPE (10, REL) +RELOC_TYPE (11, REL) +RELOC_TYPE (64, REL|DYN) +RELOC_TYPE (OLO10, REL) +RELOC_TYPE (HH22, REL) +RELOC_TYPE (HM10, REL) +RELOC_TYPE (LM22, REL) +RELOC_TYPE (PC_HH22, REL) +RELOC_TYPE (PC_HM10, REL) +RELOC_TYPE (PC_LM22, REL) +RELOC_TYPE (WDISP16, REL) +RELOC_TYPE (WDISP19, REL) +RELOC_TYPE (GLOB_JMP, EXEC|DYN) +RELOC_TYPE (7, REL) +RELOC_TYPE (5, REL) +RELOC_TYPE (6, REL) +RELOC_TYPE (DISP64, REL) +RELOC_TYPE (PLT64, REL) +RELOC_TYPE (HIX22, REL) +RELOC_TYPE (LOX10, REL) +RELOC_TYPE (H44, REL) +RELOC_TYPE (M44, REL) +RELOC_TYPE (L44, REL) +RELOC_TYPE (REGISTER, REL) +RELOC_TYPE (UA64, REL) +RELOC_TYPE (UA16, REL) +RELOC_TYPE (TLS_GD_HI22, REL) +RELOC_TYPE (TLS_GD_LO10, REL) +RELOC_TYPE (TLS_GD_ADD, REL) +RELOC_TYPE (TLS_GD_CALL, REL) +RELOC_TYPE (TLS_LDM_HI22, REL) +RELOC_TYPE (TLS_LDM_LO10, REL) +RELOC_TYPE (TLS_LDM_ADD, REL) +RELOC_TYPE (TLS_LDM_CALL, REL) +RELOC_TYPE (TLS_LDO_HIX22, REL) +RELOC_TYPE (TLS_LDO_LOX10, REL) +RELOC_TYPE (TLS_LDO_ADD, REL) +RELOC_TYPE (TLS_IE_HI22, REL) +RELOC_TYPE (TLS_IE_LO10, REL) +RELOC_TYPE (TLS_IE_LD, REL) +RELOC_TYPE (TLS_IE_LDX, REL) +RELOC_TYPE (TLS_IE_ADD, REL) +RELOC_TYPE (TLS_LE_HIX22, REL) +RELOC_TYPE (TLS_LE_LOX10, REL) +RELOC_TYPE (TLS_DTPMOD32, DYN) +RELOC_TYPE (TLS_DTPMOD64, DYN) +RELOC_TYPE (TLS_DTPOFF32, DYN) +RELOC_TYPE (TLS_DTPOFF64, DYN) +RELOC_TYPE (TLS_TPOFF32, DYN) +RELOC_TYPE (TLS_TPOFF64, DYN) +RELOC_TYPE (GOTDATA_HIX22, REL) +RELOC_TYPE (GOTDATA_LOX10, REL) +RELOC_TYPE (GOTDATA_OP_HIX22, DYN) +RELOC_TYPE (GOTDATA_OP_LOX10, DYN) +RELOC_TYPE (GOTDATA_OP, DYN) +RELOC_TYPE (H34, REL) +RELOC_TYPE (SIZE32, REL) +RELOC_TYPE (SIZE64, REL) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (GNU_VTENTRY, REL) +RELOC_TYPE (REV32, REL) diff --git a/backends/sparc_retval.c b/backends/sparc_retval.c new file mode 100644 index 00000000..e1b17753 --- /dev/null +++ b/backends/sparc_retval.c @@ -0,0 +1,159 @@ +/* Function return value location for SPARC. + Copyright (C) 2006-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND sparc_ +#include "libebl_CPU.h" + + +/* %o0, or pair %o0, %o1. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %f0 or pair %f0, %f1, or quad %f0..%f3. */ +static const Dwarf_Op loc_fpreg[] = + { + { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 4 }, + { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 4 }, + }; +#define nloc_fpreg 1 +#define nloc_fpregpair 4 +#define nloc_fpregquad 8 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %o0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg8, .number = 0 } + }; +#define nloc_aggregate 1 + +int +sparc_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + uint8_t asize; + Dwarf_Die cudie; + if ((tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + && dwarf_diecu (typedie, &cudie, &asize, NULL) != NULL) + size = asize; + else + return -1; + } + } + + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + if (encoding == DW_ATE_float) + { + *locp = loc_fpreg; + if (size <= 4) + return nloc_fpreg; + if (size <= 8) + return nloc_fpregpair; + if (size <= 16) + return nloc_fpregquad; + } + } + if (size <= 8) + { + intreg: + *locp = loc_intreg; + return size <= 4 ? nloc_intreg : nloc_intregpair; + } + + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_aggregate_size (typedie, &size) == 0 + && size > 0 && size <= 8) + goto intreg; + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/sparc_symbol.c b/backends/sparc_symbol.c new file mode 100644 index 00000000..ec11dc97 --- /dev/null +++ b/backends/sparc_symbol.c @@ -0,0 +1,148 @@ +/* SPARC specific symbolic name handling. + Copyright (C) 2002, 2003, 2005, 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + Written by Jakub Jelinek <jakub@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND sparc_ +#include "libebl_CPU.h" + +/* Check for the simple reloc types. */ +Elf_Type +sparc_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_SPARC_8: + return ELF_T_BYTE; + case R_SPARC_16: + case R_SPARC_UA16: + return ELF_T_HALF; + case R_SPARC_32: + case R_SPARC_UA32: + return ELF_T_WORD; + case R_SPARC_64: + case R_SPARC_UA64: + return ELF_T_XWORD; + default: + return ELF_T_NUM; + } +} + +/* Check whether machine flags are valid. */ +bool +sparc_machine_flag_check (GElf_Word flags) +{ + return ((flags &~ (EF_SPARCV9_MM + | EF_SPARC_LEDATA + | EF_SPARC_32PLUS + | EF_SPARC_SUN_US1 + | EF_SPARC_SUN_US3)) == 0); +} + +bool +sparc_check_special_section (Ebl *ebl, + int ndx __attribute__ ((unused)), + const GElf_Shdr *shdr, + const char *sname __attribute__ ((unused))) +{ + if ((shdr->sh_flags & (SHF_WRITE | SHF_EXECINSTR)) + == (SHF_WRITE | SHF_EXECINSTR)) + { + /* This is ordinarily flagged, but is valid for a PLT on SPARC. + + Look for the SHT_DYNAMIC section and the DT_PLTGOT tag in it. + Its d_ptr should match the .plt section's sh_addr. */ + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr scn_shdr; + if (likely (gelf_getshdr (scn, &scn_shdr) != NULL) + && scn_shdr.sh_type == SHT_DYNAMIC + && scn_shdr.sh_entsize != 0) + { + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL) + for (size_t i = 0; i < data->d_size / scn_shdr.sh_entsize; ++i) + { + GElf_Dyn dyn; + if (unlikely (gelf_getdyn (data, i, &dyn) == NULL)) + break; + if (dyn.d_tag == DT_PLTGOT) + return dyn.d_un.d_ptr == shdr->sh_addr; + } + break; + } + } + } + + return false; +} + +const char * +sparc_symbol_type_name (int type, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (type) + { + case STT_SPARC_REGISTER: + return "SPARC_REGISTER"; + } + return NULL; +} + +const char * +sparc_dynamic_tag_name (int64_t tag, + char *buf __attribute__ ((unused)), + size_t len __attribute__ ((unused))) +{ + switch (tag) + { + case DT_SPARC_REGISTER: + return "SPARC_REGISTER"; + } + return NULL; +} + +bool +sparc_dynamic_tag_check (int64_t tag) +{ + switch (tag) + { + case DT_SPARC_REGISTER: + return true; + } + return false; +} diff --git a/backends/tilegx_corenote.c b/backends/tilegx_corenote.c new file mode 100644 index 00000000..be3e7dbf --- /dev/null +++ b/backends/tilegx_corenote.c @@ -0,0 +1,64 @@ +/* TILE-Gx specific core note handling. + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND tilegx_ +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 56, .bits = 64 }, /* r0-r55 */ + { .offset = 56 * 8, .regno = 64, .count = 1, .bits = 64 } /* pc */ + }; +#define PRSTATUS_REGS_SIZE (57 * 8) + +#define ULONG uint64_t +#define ALIGN_ULONG 8 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_LONG ELF_T_SXWORD +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#include "linux-core-note.c" diff --git a/backends/tilegx_init.c b/backends/tilegx_init.c new file mode 100644 index 00000000..858798bf --- /dev/null +++ b/backends/tilegx_init.c @@ -0,0 +1,60 @@ +/* Initialization of TILE-Gx specific backend library. + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND tilegx_ +#define RELOC_PREFIX R_TILEGX_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on tilegx_reloc.def. */ +#include "common-reloc.c" + +const char * +tilegx_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "TILE-Gx"; + tilegx_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, core_note); + + return MODVERSION; +} diff --git a/backends/tilegx_regs.c b/backends/tilegx_regs.c new file mode 100644 index 00000000..b1e17439 --- /dev/null +++ b/backends/tilegx_regs.c @@ -0,0 +1,129 @@ +/* Register names and numbers for TILE-Gx DWARF. + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <dwarf.h> + +#define BACKEND tilegx_ +#include "libebl_CPU.h" + +ssize_t +tilegx_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 65; + + if (regno < 0 || regno > 64 || namelen < 5) + return -1; + + *prefix = ""; + *setname = "integer"; + *bits = 64; + + switch (regno) + { + case 0 ... 9: + *type = DW_ATE_signed; + name[0] = 'r'; + name[1] = regno + '0'; + namelen = 2; + break; + + case 10 ... 52: + *type = DW_ATE_signed; + name[0] = 'r'; + name[1] = regno / 10 + '0'; + name[2] = regno % 10 + '0'; + namelen = 3; + break; + + case 53: + *type = DW_ATE_address; + return stpcpy (name, "tp") + 1 - name; + + case 54: + *type = DW_ATE_address; + return stpcpy (name, "sp") + 1 - name; + + case 55: + *type = DW_ATE_address; + return stpcpy (name, "lr") + 1 - name; + + case 56: + *type = DW_ATE_unsigned; + return stpcpy (name, "sn") + 1 - name; + + case 57: + *type = DW_ATE_unsigned; + return stpcpy (name, "idn0") + 1 - name; + + case 58: + *type = DW_ATE_unsigned; + return stpcpy (name, "idn1") + 1 - name; + + case 59: + *type = DW_ATE_unsigned; + return stpcpy (name, "udn0") + 1 - name; + + case 60: + *type = DW_ATE_unsigned; + return stpcpy (name, "udn1") + 1 - name; + + case 61: + *type = DW_ATE_unsigned; + return stpcpy (name, "udn2") + 1 - name; + + case 62: + *type = DW_ATE_unsigned; + return stpcpy (name, "udn3") + 1 - name; + + case 63: + *type = DW_ATE_unsigned; + return stpcpy (name, "zero") + 1 - name; + + case 64: + *type = DW_ATE_address; + return stpcpy (name, "pc") + 1 - name; + + /* Can't happen. */ + default: + *setname = NULL; + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/tilegx_reloc.def b/backends/tilegx_reloc.def new file mode 100644 index 00000000..9736286e --- /dev/null +++ b/backends/tilegx_reloc.def @@ -0,0 +1,120 @@ +/* List the relocation types for tilegx. -*- C -*- + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (64, REL|EXEC|DYN) +RELOC_TYPE (32, REL|EXEC|DYN) +RELOC_TYPE (16, REL|EXEC|DYN) +RELOC_TYPE (8, REL|EXEC|DYN) +RELOC_TYPE (64_PCREL, REL) +RELOC_TYPE (32_PCREL, REL) +RELOC_TYPE (16_PCREL, REL) +RELOC_TYPE (8_PCREL, REL) +RELOC_TYPE (HW0, REL) +RELOC_TYPE (HW1, REL) +RELOC_TYPE (HW2, REL) +RELOC_TYPE (HW3, REL) +RELOC_TYPE (HW0_LAST, REL) +RELOC_TYPE (HW1_LAST, REL) +RELOC_TYPE (HW2_LAST, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (BROFF_X1, REL) +RELOC_TYPE (JUMPOFF_X1, REL) +RELOC_TYPE (JUMPOFF_X1_PLT, REL) +RELOC_TYPE (IMM8_X0, REL) +RELOC_TYPE (IMM8_Y0, REL) +RELOC_TYPE (IMM8_X1, REL) +RELOC_TYPE (IMM8_Y1, REL) +RELOC_TYPE (DEST_IMM8_X1, REL) +RELOC_TYPE (MT_IMM14_X1, REL) +RELOC_TYPE (MF_IMM14_X1, REL) +RELOC_TYPE (MMSTART_X0, REL) +RELOC_TYPE (MMEND_X0, REL) +RELOC_TYPE (SHAMT_X0, REL) +RELOC_TYPE (SHAMT_X1, REL) +RELOC_TYPE (SHAMT_Y0, REL) +RELOC_TYPE (SHAMT_Y1, REL) +RELOC_TYPE (IMM16_X0_HW0, REL) +RELOC_TYPE (IMM16_X1_HW0, REL) +RELOC_TYPE (IMM16_X0_HW1, REL) +RELOC_TYPE (IMM16_X1_HW1, REL) +RELOC_TYPE (IMM16_X0_HW2, REL) +RELOC_TYPE (IMM16_X1_HW2, REL) +RELOC_TYPE (IMM16_X0_HW3, REL) +RELOC_TYPE (IMM16_X1_HW3, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST, REL) +RELOC_TYPE (IMM16_X0_HW2_LAST, REL) +RELOC_TYPE (IMM16_X1_HW2_LAST, REL) +RELOC_TYPE (IMM16_X0_HW0_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW0_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW1_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW1_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW2_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW2_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW3_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW3_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW2_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X1_HW2_LAST_PCREL, REL) +RELOC_TYPE (IMM16_X0_HW0_GOT, REL) +RELOC_TYPE (IMM16_X1_HW0_GOT, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST_GOT, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST_GOT, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST_GOT, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST_GOT, REL) +RELOC_TYPE (IMM16_X0_HW0_TLS_GD, REL) +RELOC_TYPE (IMM16_X1_HW0_TLS_GD, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST_TLS_GD, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST_TLS_GD, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST_TLS_GD, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST_TLS_GD, REL) +RELOC_TYPE (IMM16_X0_HW0_TLS_IE, REL) +RELOC_TYPE (IMM16_X1_HW0_TLS_IE, REL) +RELOC_TYPE (IMM16_X0_HW0_LAST_TLS_IE, REL) +RELOC_TYPE (IMM16_X1_HW0_LAST_TLS_IE, REL) +RELOC_TYPE (IMM16_X0_HW1_LAST_TLS_IE, REL) +RELOC_TYPE (IMM16_X1_HW1_LAST_TLS_IE, REL) +RELOC_TYPE (TLS_DTPMOD64, EXEC|DYN) +RELOC_TYPE (TLS_DTPOFF64, EXEC|DYN) +RELOC_TYPE (TLS_TPOFF64, EXEC|DYN) +RELOC_TYPE (TLS_DTPMOD32, EXEC|DYN) +RELOC_TYPE (TLS_DTPOFF32, EXEC|DYN) +RELOC_TYPE (TLS_TPOFF32, EXEC|DYN) +RELOC_TYPE (GNU_VTINHERIT, REL) +RELOC_TYPE (GNU_VTENTRY, REL) diff --git a/backends/tilegx_retval.c b/backends/tilegx_retval.c new file mode 100644 index 00000000..db81a20b --- /dev/null +++ b/backends/tilegx_retval.c @@ -0,0 +1,154 @@ +/* Function return value location for Linux/TILE-Gx ABI. + Copyright (C) 2012 Tilera Corporation + Copyright (C) 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND tilegx_ +#include "libebl_CPU.h" + + +/* r0. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 } + }; +#define nloc_intreg 1 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in r0. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + +int +tilegx_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + if (tag == DW_TAG_base_type) + { + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + } + } + + /* Small enough structs are passed directly in registers R0 ... R7. */ + if (size <= 8) + { + intreg: + *locp = loc_intreg; + return nloc_intreg; + } + + /* Else fall through. */ + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + aggregate: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_array_type: + case DW_TAG_string_type: + if (dwarf_aggregate_size (typedie, &size) == 0 && size <= 8) + { + if (tag == DW_TAG_array_type) + { + Dwarf_Attribute attr_mem, *attr; + /* Check if it's a character array. */ + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + if (tag != DW_TAG_base_type) + goto aggregate; + if (dwarf_formudata (dwarf_attr_integrate (typedie, + DW_AT_byte_size, + &attr_mem), + &size) != 0) + return -1; + if (size != 1) + goto aggregate; + } + goto intreg; + } + goto aggregate; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/tilegx_symbol.c b/backends/tilegx_symbol.c new file mode 100644 index 00000000..b6533266 --- /dev/null +++ b/backends/tilegx_symbol.c @@ -0,0 +1,57 @@ +/* TILEGX-specific symbolic name handling. + Copyright (C) 2012 Tilera Corporation + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <stddef.h> + +#define BACKEND tilegx_ +#include "libebl_CPU.h" + +/* Check for the simple reloc types. */ +Elf_Type +tilegx_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_TILEGX_64: + return ELF_T_SXWORD; + case R_TILEGX_32: + return ELF_T_SWORD; + case R_TILEGX_16: + return ELF_T_HALF; + case R_TILEGX_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} diff --git a/backends/x86_64_cfi.c b/backends/x86_64_cfi.c new file mode 100644 index 00000000..6db8ac44 --- /dev/null +++ b/backends/x86_64_cfi.c @@ -0,0 +1,63 @@ +/* x86-64 ABI-specified defaults for DWARF CFI. + Copyright (C) 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <dwarf.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +int +x86_64_abi_cfi (Ebl *ebl __attribute__ ((unused)), Dwarf_CIE *abi_info) +{ + static const uint8_t abi_cfi[] = + { + /* Call-saved regs. */ + DW_CFA_same_value, ULEB128_7 (0), /* %rbx */ + DW_CFA_same_value, ULEB128_7 (6), /* %rbp */ + DW_CFA_same_value, ULEB128_7 (12), /* %r12 */ + DW_CFA_same_value, ULEB128_7 (13), /* %r13 */ + DW_CFA_same_value, ULEB128_7 (14), /* %r14 */ + DW_CFA_same_value, ULEB128_7 (15), /* %r15 */ + DW_CFA_same_value, ULEB128_7 (16), /* %r16 */ + + /* The CFA is the SP. */ + DW_CFA_val_offset, ULEB128_7 (7), ULEB128_7 (0), + }; + + abi_info->initial_instructions = abi_cfi; + abi_info->initial_instructions_end = &abi_cfi[sizeof abi_cfi]; + abi_info->data_alignment_factor = 8; + + abi_info->return_address_register = 16; /* %rip */ + + return 0; +} diff --git a/backends/x86_64_corenote.c b/backends/x86_64_corenote.c new file mode 100644 index 00000000..f9d8db45 --- /dev/null +++ b/backends/x86_64_corenote.c @@ -0,0 +1,112 @@ +/* x86-64 specific core note handling. + Copyright (C) 2005, 2007, 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <elf.h> +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> +#include <sys/time.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * 8, .regno = dwreg, .count = n, .bits = 64 } +#define SR(at, n, dwreg) \ + { .offset = at * 8, .regno = dwreg, .count = n, .bits = 16, .pad = 6 } + + GR (0, 1, 15), /* %r15 */ + GR (1, 1, 14), /* %r14 */ + GR (2, 1, 13), /* %r13 */ + GR (3, 1, 12), /* %r12 */ + GR (4, 1, 6), /* %rbp */ + GR (5, 1, 3), /* %rbx */ + GR (6, 1, 11), /* %r11 */ + GR (7, 1, 10), /* %r10 */ + GR (8, 1, 9), /* %r9 */ + GR (9, 1, 8), /* %r8 */ + GR (10,1, 0), /* %rax */ + GR (11,1, 2), /* %rcx */ + GR (12,1, 1), /* %rdx */ + GR (13,2, 4), /* %rsi-%rdi */ + /* 15,1, orig_rax */ + GR (16,1, 16), /* %rip */ + SR (17,1, 51), /* %cs */ + GR (18,1, 49), /* %rFLAGS */ + GR (19,1, 7), /* %rsp */ + SR (20,1, 52), /* %ss */ + GR (21,2, 58), /* %fs.base-%gs.base */ + SR (23,1, 53), /* %ds */ + SR (24,1, 50), /* %es */ + SR (25,2, 54), /* %fs-%gs */ + +#undef GR +#undef SR + }; +#define PRSTATUS_REGS_SIZE (27 * 8) + +#define ULONG uint64_t +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_ULONG 8 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_SWORD +#define TYPE_GID_T ELF_T_SWORD + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_rax", .type = ELF_T_SXWORD, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (8 * 15), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 65, .count = 2, .bits = 16 }, /* fcw-fsw */ + { .offset = 24, .regno = 64, .count = 1, .bits = 32 }, /* mxcsr */ + { .offset = 32, .regno = 33, .count = 8, .bits = 80, .pad = 6 }, /* stN */ + { .offset = 32 + 128, .regno = 17, .count = 16, .bits = 128 }, /* xmm */ + }; +#define FPREGSET_SIZE 512 + +#define EXTRA_NOTES EXTRA_NOTES_IOPERM + +#include "x86_corenote.c" +#include "linux-core-note.c" diff --git a/backends/x86_64_init.c b/backends/x86_64_init.c new file mode 100644 index 00000000..b885558b --- /dev/null +++ b/backends/x86_64_init.c @@ -0,0 +1,68 @@ +/* Initialization of x86-64 specific backend library. + Copyright (C) 2002-2009, 2013 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND x86_64_ +#define RELOC_PREFIX R_X86_64_ +#include "libebl_CPU.h" + +/* This defines the common reloc hooks based on x86_64_reloc.def. */ +#include "common-reloc.c" + +const char * +x86_64_init (elf, machine, eh, ehlen) + Elf *elf __attribute__ ((unused)); + GElf_Half machine __attribute__ ((unused)); + Ebl *eh; + size_t ehlen; +{ + /* Check whether the Elf_BH object has a sufficent size. */ + if (ehlen < sizeof (Ebl)) + return NULL; + + /* We handle it. */ + eh->name = "AMD x86-64"; + x86_64_init_reloc (eh); + HOOK (eh, reloc_simple_type); + HOOK (eh, core_note); + HOOK (eh, return_value_location); + HOOK (eh, register_info); + HOOK (eh, syscall_abi); + HOOK (eh, auxv_info); + HOOK (eh, disasm); + HOOK (eh, abi_cfi); + /* gcc/config/ #define DWARF_FRAME_REGISTERS. */ + eh->frame_nregs = 17; + HOOK (eh, set_initial_registers_tid); + + return MODVERSION; +} diff --git a/backends/x86_64_initreg.c b/backends/x86_64_initreg.c new file mode 100644 index 00000000..db9216ed --- /dev/null +++ b/backends/x86_64_initreg.c @@ -0,0 +1,73 @@ +/* Fetch live process registers from TID. + Copyright (C) 2013 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#ifdef __x86_64__ +# include <sys/user.h> +# include <sys/ptrace.h> +#endif + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +bool +x86_64_set_initial_registers_tid (pid_t tid __attribute__ ((unused)), + ebl_tid_registers_t *setfunc __attribute__ ((unused)), + void *arg __attribute__ ((unused))) +{ +#if !defined(__x86_64__) || !defined(__linux__) + return false; +#else /* __x86_64__ */ + struct user_regs_struct user_regs; + if (ptrace (PTRACE_GETREGS, tid, NULL, &user_regs) != 0) + return false; + Dwarf_Word dwarf_regs[17]; + dwarf_regs[0] = user_regs.rax; + dwarf_regs[1] = user_regs.rdx; + dwarf_regs[2] = user_regs.rcx; + dwarf_regs[3] = user_regs.rbx; + dwarf_regs[4] = user_regs.rsi; + dwarf_regs[5] = user_regs.rdi; + dwarf_regs[6] = user_regs.rbp; + dwarf_regs[7] = user_regs.rsp; + dwarf_regs[8] = user_regs.r8; + dwarf_regs[9] = user_regs.r9; + dwarf_regs[10] = user_regs.r10; + dwarf_regs[11] = user_regs.r11; + dwarf_regs[12] = user_regs.r12; + dwarf_regs[13] = user_regs.r13; + dwarf_regs[14] = user_regs.r14; + dwarf_regs[15] = user_regs.r15; + dwarf_regs[16] = user_regs.rip; + return setfunc (0, 17, dwarf_regs, arg); +#endif /* __x86_64__ */ +} diff --git a/backends/x86_64_regs.c b/backends/x86_64_regs.c new file mode 100644 index 00000000..2172d9f1 --- /dev/null +++ b/backends/x86_64_regs.c @@ -0,0 +1,185 @@ +/* Register names and numbers for x86-64 DWARF. + Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> +#include <string.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +ssize_t +x86_64_register_info (Ebl *ebl __attribute__ ((unused)), + int regno, char *name, size_t namelen, + const char **prefix, const char **setname, + int *bits, int *type) +{ + if (name == NULL) + return 67; + + if (regno < 0 || regno > 66 || namelen < 7) + return -1; + + *prefix = "%"; + *bits = 64; + *type = DW_ATE_unsigned; + if (regno < 17) + { + *setname = "integer"; + *type = DW_ATE_signed; + } + else if (regno < 33) + { + *setname = "SSE"; + *bits = 128; + } + else if (regno < 41) + { + *setname = "x87"; + *type = DW_ATE_float; + *bits = 80; + } + else if (regno < 49) + *setname = "MMX"; + else if (regno > 49 && regno < 60) + { + *setname = "segment"; + *bits = 16; + } + else + *setname = "control"; + + switch (regno) + { + static const char baseregs[][2] = + { + "ax", "dx", "cx", "bx", "si", "di", "bp", "sp" + }; + + case 6 ... 7: + *type = DW_ATE_address; + case 0 ... 5: + name[0] = 'r'; + name[1] = baseregs[regno][0]; + name[2] = baseregs[regno][1]; + namelen = 3; + break; + + case 8 ... 9: + name[0] = 'r'; + name[1] = regno - 8 + '8'; + namelen = 2; + break; + + case 10 ... 15: + name[0] = 'r'; + name[1] = '1'; + name[2] = regno - 10 + '0'; + namelen = 3; + break; + + case 16: + *type = DW_ATE_address; + name[0] = 'r'; + name[1] = 'i'; + name[2] = 'p'; + namelen = 3; + break; + + case 17 ... 26: + name[0] = 'x'; + name[1] = 'm'; + name[2] = 'm'; + name[3] = regno - 17 + '0'; + namelen = 4; + break; + + case 27 ... 32: + name[0] = 'x'; + name[1] = 'm'; + name[2] = 'm'; + name[3] = '1'; + name[4] = regno - 27 + '0'; + namelen = 5; + break; + + case 33 ... 40: + name[0] = 's'; + name[1] = 't'; + name[2] = regno - 33 + '0'; + namelen = 3; + break; + + case 41 ... 48: + name[0] = 'm'; + name[1] = 'm'; + name[2] = regno - 41 + '0'; + namelen = 3; + break; + + case 50 ... 55: + name[0] = "ecsdfg"[regno - 50]; + name[1] = 's'; + namelen = 2; + break; + + case 58 ... 59: + *type = DW_ATE_address; + *bits = 64; + name[0] = regno - 58 + 'f'; + return stpcpy (&name[1], "s.base") + 1 - name; + + case 49: + *setname = "integer"; + return stpcpy (name, "rflags") + 1 - name; + case 62: + return stpcpy (name, "tr") + 1 - name; + case 63: + return stpcpy (name, "ldtr") + 1 - name; + case 64: + return stpcpy (name, "mxcsr") + 1 - name; + + case 65 ... 66: + *bits = 16; + name[0] = 'f'; + name[1] = "cs"[regno - 65]; + name[2] = 'w'; + namelen = 3; + break; + + default: + return 0; + } + + name[namelen++] = '\0'; + return namelen; +} diff --git a/backends/x86_64_reloc.def b/backends/x86_64_reloc.def new file mode 100644 index 00000000..8ed98f64 --- /dev/null +++ b/backends/x86_64_reloc.def @@ -0,0 +1,63 @@ +/* List the relocation types for x86-64. -*- C -*- + Copyright (C) 2000, 2001, 2002, 2003, 2005, 2009 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +/* NAME, REL|EXEC|DYN */ + +RELOC_TYPE (NONE, 0) +RELOC_TYPE (64, REL|EXEC|DYN) +RELOC_TYPE (PC32, REL|EXEC|DYN) +RELOC_TYPE (GOT32, REL) +RELOC_TYPE (PLT32, REL) +RELOC_TYPE (COPY, EXEC) +RELOC_TYPE (GLOB_DAT, EXEC|DYN) +RELOC_TYPE (JUMP_SLOT, EXEC|DYN) +RELOC_TYPE (RELATIVE, EXEC|DYN) +RELOC_TYPE (GOTPCREL, REL) +RELOC_TYPE (32, REL|EXEC|DYN) +RELOC_TYPE (32S, REL) +RELOC_TYPE (16, REL) +RELOC_TYPE (PC16, REL) +RELOC_TYPE (8, REL) +RELOC_TYPE (PC8, REL) +RELOC_TYPE (DTPMOD64, EXEC|DYN) +RELOC_TYPE (DTPOFF64, EXEC|DYN) +RELOC_TYPE (TPOFF64, EXEC|DYN) +RELOC_TYPE (TLSGD, REL) +RELOC_TYPE (TLSLD, REL) +RELOC_TYPE (DTPOFF32, REL) +RELOC_TYPE (GOTTPOFF, REL) +RELOC_TYPE (TPOFF32, REL) +RELOC_TYPE (PC64, REL|EXEC|DYN) +RELOC_TYPE (GOTOFF64, REL) +RELOC_TYPE (GOTPC32, REL) +RELOC_TYPE (SIZE32, REL|EXEC|DYN) +RELOC_TYPE (SIZE64, REL|EXEC|DYN) +RELOC_TYPE (GOTPC32_TLSDESC, REL) +RELOC_TYPE (TLSDESC_CALL, REL) +RELOC_TYPE (TLSDESC, REL|EXEC|DYN) +RELOC_TYPE (IRELATIVE, EXEC|DYN) diff --git a/backends/x86_64_retval.c b/backends/x86_64_retval.c new file mode 100644 index 00000000..b3799ae0 --- /dev/null +++ b/backends/x86_64_retval.c @@ -0,0 +1,194 @@ +/* Function return value location for Linux/x86-64 ABI. + Copyright (C) 2005-2010, 2014 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <dwarf.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + + +/* %rax, or pair %rax, %rdx. */ +static const Dwarf_Op loc_intreg[] = + { + { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 }, + { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 }, + }; +#define nloc_intreg 1 +#define nloc_intregpair 4 + +/* %st(0), or pair %st(0), %st(1). */ +static const Dwarf_Op loc_x87reg[] = + { + { .atom = DW_OP_regx, .number = 33 }, + { .atom = DW_OP_piece, .number = 10 }, + { .atom = DW_OP_regx, .number = 34 }, + { .atom = DW_OP_piece, .number = 10 }, + }; +#define nloc_x87reg 1 +#define nloc_x87regpair 4 + +/* %xmm0, or pair %xmm0, %xmm1. */ +static const Dwarf_Op loc_ssereg[] = + { + { .atom = DW_OP_reg17 }, { .atom = DW_OP_piece, .number = 16 }, + { .atom = DW_OP_reg18 }, { .atom = DW_OP_piece, .number = 16 }, + }; +#define nloc_ssereg 1 +#define nloc_sseregpair 4 + +/* The return value is a structure and is actually stored in stack space + passed in a hidden argument by the caller. But, the compiler + helpfully returns the address of that space in %rax. */ +static const Dwarf_Op loc_aggregate[] = + { + { .atom = DW_OP_breg0, .number = 0 } + }; +#define nloc_aggregate 1 + + +int +x86_64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) +{ + /* Start with the function's type, and get the DW_AT_type attribute, + which is the type of the return value. */ + Dwarf_Die die_mem, *typedie = &die_mem; + int tag = dwarf_peeled_die_type (functypedie, typedie); + if (tag <= 0) + return tag; + + Dwarf_Word size; + switch (tag) + { + case -1: + return -1; + + case DW_TAG_subrange_type: + if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size)) + { + Dwarf_Attribute attr_mem, *attr; + attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem); + typedie = dwarf_formref_die (attr, &die_mem); + tag = DWARF_TAG_OR_RETURN (typedie); + } + /* Fall through. */ + + case DW_TAG_base_type: + case DW_TAG_enumeration_type: + case DW_TAG_pointer_type: + case DW_TAG_ptr_to_member_type: + { + Dwarf_Attribute attr_mem; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size, + &attr_mem), &size) != 0) + { + if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type) + size = 8; + else + return -1; + } + } + + if (tag == DW_TAG_base_type) + { + Dwarf_Attribute attr_mem; + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding, + &attr_mem), + &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_complex_float: + switch (size) + { + case 4 * 2: /* complex float */ + case 8 * 2: /* complex double */ + *locp = loc_ssereg; + return nloc_sseregpair; + case 16 * 2: /* complex long double */ + *locp = loc_x87reg; + return nloc_x87regpair; + } + return -2; + + case DW_ATE_float: + switch (size) + { + case 4: /* float */ + case 8: /* double */ + *locp = loc_ssereg; + return nloc_ssereg; + case 16: /* long double */ + /* XXX distinguish __float128, which is sseregpair?? */ + *locp = loc_x87reg; + return nloc_x87reg; + } + return -2; + } + } + + intreg: + *locp = loc_intreg; + if (size <= 8) + return nloc_intreg; + if (size <= 16) + return nloc_intregpair; + + large: + *locp = loc_aggregate; + return nloc_aggregate; + + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_union_type: + case DW_TAG_array_type: + if (dwarf_aggregate_size (typedie, &size) != 0) + goto large; + if (size > 16) + goto large; + + /* XXX + Must examine the fields in picayune ways to determine the + actual answer. This will be right for small C structs + containing integer types and similarly simple cases. + */ + + goto intreg; + } + + /* XXX We don't have a good way to return specific errors from ebl calls. + This value means we do not understand the type, but it is well-formed + DWARF and might be valid. */ + return -2; +} diff --git a/backends/x86_64_symbol.c b/backends/x86_64_symbol.c new file mode 100644 index 00000000..1622461d --- /dev/null +++ b/backends/x86_64_symbol.c @@ -0,0 +1,60 @@ +/* x86_64 specific symbolic name handling. + Copyright (C) 2002, 2005 Red Hat, Inc. + This file is part of elfutils. + Written by Ulrich Drepper <drepper@redhat.com>, 2002. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <elf.h> +#include <stddef.h> + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +/* Check for the simple reloc types. */ +Elf_Type +x86_64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type) +{ + switch (type) + { + case R_X86_64_64: + return ELF_T_XWORD; + case R_X86_64_32: + return ELF_T_WORD; + case R_X86_64_32S: + return ELF_T_SWORD; + case R_X86_64_16: + return ELF_T_HALF; + case R_X86_64_8: + return ELF_T_BYTE; + default: + return ELF_T_NUM; + } +} diff --git a/backends/x86_64_syscall.c b/backends/x86_64_syscall.c new file mode 100644 index 00000000..0deb8bad --- /dev/null +++ b/backends/x86_64_syscall.c @@ -0,0 +1,50 @@ +/* Linux/x86-64 system call ABI in DWARF register numbers. + Copyright (C) 2008 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define BACKEND x86_64_ +#include "libebl_CPU.h" + +int +x86_64_syscall_abi (Ebl *ebl __attribute__ ((unused)), + int *sp, int *pc, int *callno, int args[6]) +{ + *sp = 7; /* %rsp */ + *pc = 16; /* %rip */ + *callno = 0; /* %rax */ + args[0] = 5; /* %rdi */ + args[1] = 4; /* %rsi */ + args[2] = 1; /* %rdx */ + args[3] = 10; /* %r10 */ + args[4] = 8; /* %r8 */ + args[5] = 9; /* %r9 */ + return 0; +} diff --git a/backends/x86_corenote.c b/backends/x86_corenote.c new file mode 100644 index 00000000..629462c3 --- /dev/null +++ b/backends/x86_corenote.c @@ -0,0 +1,51 @@ +/* x86-specific core note handling, pieces common to x86-64 and i386. + Copyright (C) 2005-2010 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#define EXTRA_NOTES_IOPERM \ + case NT_386_IOPERM: \ + return ioperm_info (nhdr->n_descsz, \ + regs_offset, nregloc, reglocs, nitems, items); + +static int +ioperm_info (GElf_Word descsz, GElf_Word *regs_offset, + size_t *nregloc, const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **items) +{ + static const Ebl_Core_Item ioperm_item = + { .type = ELF_T_WORD, .format = 'b', .name = "ioperm" }; + + if (descsz % 4 != 0) + return 0; + + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + *nitems = 1; + *items = &ioperm_item; + return 1; +} |