X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fppc-linux-tdep.c;h=324cef74c2a83a421ccad6b4592d74a9594e3f9e;hb=f2db237aa14bae7e5e7a7c4c85e4c2c84b11a30e;hp=5cf0f236cf8a138783e7fff04f430e911b55649d;hpb=3e8c568d4fc67da218a87d51da180bba5ad585f1;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 5cf0f236cf..324cef74c2 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -8,7 +8,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,9 +17,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "frame.h" @@ -40,51 +38,6 @@ #include "frame-unwind.h" #include "tramp-frame.h" -/* From , values for PT_NIP, PT_R1, and PT_LNK */ -#define PPC_LINUX_PT_R0 0 -#define PPC_LINUX_PT_R1 1 -#define PPC_LINUX_PT_R2 2 -#define PPC_LINUX_PT_R3 3 -#define PPC_LINUX_PT_R4 4 -#define PPC_LINUX_PT_R5 5 -#define PPC_LINUX_PT_R6 6 -#define PPC_LINUX_PT_R7 7 -#define PPC_LINUX_PT_R8 8 -#define PPC_LINUX_PT_R9 9 -#define PPC_LINUX_PT_R10 10 -#define PPC_LINUX_PT_R11 11 -#define PPC_LINUX_PT_R12 12 -#define PPC_LINUX_PT_R13 13 -#define PPC_LINUX_PT_R14 14 -#define PPC_LINUX_PT_R15 15 -#define PPC_LINUX_PT_R16 16 -#define PPC_LINUX_PT_R17 17 -#define PPC_LINUX_PT_R18 18 -#define PPC_LINUX_PT_R19 19 -#define PPC_LINUX_PT_R20 20 -#define PPC_LINUX_PT_R21 21 -#define PPC_LINUX_PT_R22 22 -#define PPC_LINUX_PT_R23 23 -#define PPC_LINUX_PT_R24 24 -#define PPC_LINUX_PT_R25 25 -#define PPC_LINUX_PT_R26 26 -#define PPC_LINUX_PT_R27 27 -#define PPC_LINUX_PT_R28 28 -#define PPC_LINUX_PT_R29 29 -#define PPC_LINUX_PT_R30 30 -#define PPC_LINUX_PT_R31 31 -#define PPC_LINUX_PT_NIP 32 -#define PPC_LINUX_PT_MSR 33 -#define PPC_LINUX_PT_CTR 35 -#define PPC_LINUX_PT_LNK 36 -#define PPC_LINUX_PT_XER 37 -#define PPC_LINUX_PT_CCR 38 -#define PPC_LINUX_PT_MQ 39 -#define PPC_LINUX_PT_FPR0 48 /* each FP reg occupies 2 slots in this space */ -#define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31) -#define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1) - - static CORE_ADDR ppc_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) { @@ -591,136 +544,173 @@ ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) } -/* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG) on PPC64 +/* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC GNU/Linux. Usually a function pointer's representation is simply the address - of the function. On GNU/Linux on the 64-bit PowerPC however, a - function pointer is represented by a pointer to a TOC entry. This - TOC entry contains three words, the first word is the address of - the function, the second word is the TOC pointer (r2), and the - third word is the static chain value. Throughout GDB it is - currently assumed that a function pointer contains the address of - the function, which is not easy to fix. In addition, the + of the function. On GNU/Linux on the PowerPC however, a function + pointer may be a pointer to a function descriptor. + + For PPC64, a function descriptor is a TOC entry, in a data section, + which contains three words: the first word is the address of the + function, the second word is the TOC pointer (r2), and the third word + is the static chain value. + + For PPC32, there are two kinds of function pointers: non-secure and + secure. Non-secure function pointers point directly to the + function in a code section and thus need no translation. Secure + ones (from GCC's -msecure-plt option) are in a data section and + contain one word: the address of the function. + + Throughout GDB it is currently assumed that a function pointer contains + the address of the function, which is not easy to fix. In addition, the conversion of a function address to a function pointer would require allocation of a TOC entry in the inferior's memory space, with all its drawbacks. To be able to call C++ virtual methods in the inferior (which are called via function pointers), find_function_addr uses this function to get the function address - from a function pointer. */ + from a function pointer. -/* If ADDR points at what is clearly a function descriptor, transform - it into the address of the corresponding function. Be - conservative, otherwize GDB will do the transformation on any - random addresses such as occures when there is no symbol table. */ + If ADDR points at what is clearly a function descriptor, transform + it into the address of the corresponding function, if needed. Be + conservative, otherwise GDB will do the transformation on any + random addresses such as occur when there is no symbol table. */ static CORE_ADDR -ppc64_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch, - CORE_ADDR addr, - struct target_ops *targ) +ppc_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch, + CORE_ADDR addr, + struct target_ops *targ) { + struct gdbarch_tdep *tdep; struct section_table *s = target_section_by_addr (targ, addr); + char *sect_name = NULL; + + if (!s) + return addr; + + tdep = gdbarch_tdep (gdbarch); + + switch (tdep->wordsize) + { + case 4: + sect_name = ".plt"; + break; + case 8: + sect_name = ".opd"; + break; + default: + internal_error (__FILE__, __LINE__, + _("failed internal consistency check")); + } /* Check if ADDR points to a function descriptor. */ - if (s && strcmp (s->the_bfd_section->name, ".opd") == 0) - return get_target_memory_unsigned (targ, addr, 8); + + /* NOTE: this depends on the coincidence that the address of a functions + entry point is contained in the first word of its function descriptor + for both PPC-64 and for PPC-32 with secure PLTs. */ + if ((strcmp (s->the_bfd_section->name, sect_name) == 0) + && s->the_bfd_section->flags & SEC_DATA) + return get_target_memory_unsigned (targ, addr, tdep->wordsize); return addr; } +/* This wrapper clears areas in the linux gregset not written by + ppc_collect_gregset. */ + static void -right_supply_register (struct regcache *regcache, int wordsize, int regnum, - const bfd_byte *buf) +ppc_linux_collect_gregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs, size_t len) { - regcache_raw_supply (regcache, regnum, - (buf + wordsize - register_size (current_gdbarch, regnum))); + if (regnum == -1) + memset (gregs, 0, len); + ppc_collect_gregset (regset, regcache, regnum, gregs, len); } -/* Extract the register values found in the WORDSIZED ABI GREGSET, - storing their values in REGCACHE. Note that some are left-aligned, - while others are right aligned. */ - -void -ppc_linux_supply_gregset (struct regcache *regcache, - int regnum, const void *gregs, size_t size, - int wordsize) -{ - int regi; - struct gdbarch *regcache_arch = get_regcache_arch (regcache); - struct gdbarch_tdep *regcache_tdep = gdbarch_tdep (regcache_arch); - const bfd_byte *buf = gregs; - - for (regi = 0; regi < ppc_num_gprs; regi++) - right_supply_register (regcache, wordsize, - regcache_tdep->ppc_gp0_regnum + regi, - buf + wordsize * regi); - - right_supply_register (regcache, wordsize, gdbarch_pc_regnum (regcache_arch), - buf + wordsize * PPC_LINUX_PT_NIP); - right_supply_register (regcache, wordsize, regcache_tdep->ppc_lr_regnum, - buf + wordsize * PPC_LINUX_PT_LNK); - regcache_raw_supply (regcache, regcache_tdep->ppc_cr_regnum, - buf + wordsize * PPC_LINUX_PT_CCR); - regcache_raw_supply (regcache, regcache_tdep->ppc_xer_regnum, - buf + wordsize * PPC_LINUX_PT_XER); - regcache_raw_supply (regcache, regcache_tdep->ppc_ctr_regnum, - buf + wordsize * PPC_LINUX_PT_CTR); - if (regcache_tdep->ppc_mq_regnum != -1) - right_supply_register (regcache, wordsize, regcache_tdep->ppc_mq_regnum, - buf + wordsize * PPC_LINUX_PT_MQ); - right_supply_register (regcache, wordsize, regcache_tdep->ppc_ps_regnum, - buf + wordsize * PPC_LINUX_PT_MSR); -} +/* Regset descriptions. */ +static const struct ppc_reg_offsets ppc32_linux_reg_offsets = + { + /* General-purpose registers. */ + /* .r0_offset = */ 0, + /* .gpr_size = */ 4, + /* .xr_size = */ 4, + /* .pc_offset = */ 128, + /* .ps_offset = */ 132, + /* .cr_offset = */ 152, + /* .lr_offset = */ 144, + /* .ctr_offset = */ 140, + /* .xer_offset = */ 148, + /* .mq_offset = */ 156, + + /* Floating-point registers. */ + /* .f0_offset = */ 0, + /* .fpscr_offset = */ 256, + /* .fpscr_size = */ 8, + + /* AltiVec registers. */ + /* .vr0_offset = */ 0, + /* .vrsave_offset = */ 512, + /* .vscr_offset = */ 512 + 12 + }; -static void -ppc32_linux_supply_gregset (const struct regset *regset, - struct regcache *regcache, - int regnum, const void *gregs, size_t size) -{ - ppc_linux_supply_gregset (regcache, regnum, gregs, size, 4); -} +static const struct ppc_reg_offsets ppc64_linux_reg_offsets = + { + /* General-purpose registers. */ + /* .r0_offset = */ 0, + /* .gpr_size = */ 8, + /* .xr_size = */ 8, + /* .pc_offset = */ 256, + /* .ps_offset = */ 264, + /* .cr_offset = */ 304, + /* .lr_offset = */ 288, + /* .ctr_offset = */ 280, + /* .xer_offset = */ 296, + /* .mq_offset = */ 312, + + /* Floating-point registers. */ + /* .f0_offset = */ 0, + /* .fpscr_offset = */ 256, + /* .fpscr_size = */ 8, + + /* AltiVec registers. */ + /* .vr0_offset = */ 0, + /* .vrsave_offset = */ 528, + /* .vscr_offset = */ 512 + 12 + }; -static struct regset ppc32_linux_gregset = { - NULL, ppc32_linux_supply_gregset +static const struct regset ppc32_linux_gregset = { + &ppc32_linux_reg_offsets, + ppc_supply_gregset, + ppc_linux_collect_gregset, + NULL }; -static void -ppc64_linux_supply_gregset (const struct regset *regset, - struct regcache * regcache, - int regnum, const void *gregs, size_t size) -{ - ppc_linux_supply_gregset (regcache, regnum, gregs, size, 8); -} +static const struct regset ppc64_linux_gregset = { + &ppc64_linux_reg_offsets, + ppc_supply_gregset, + ppc_linux_collect_gregset, + NULL +}; -static struct regset ppc64_linux_gregset = { - NULL, ppc64_linux_supply_gregset +static const struct regset ppc32_linux_fpregset = { + &ppc32_linux_reg_offsets, + ppc_supply_fpregset, + ppc_collect_fpregset, + NULL }; -void -ppc_linux_supply_fpregset (const struct regset *regset, - struct regcache * regcache, - int regnum, const void *fpset, size_t size) +const struct regset * +ppc_linux_gregset (int wordsize) { - int regi; - struct gdbarch *regcache_arch = get_regcache_arch (regcache); - struct gdbarch_tdep *regcache_tdep = gdbarch_tdep (regcache_arch); - const bfd_byte *buf = fpset; - - if (! ppc_floating_point_unit_p (regcache_arch)) - return; - - for (regi = 0; regi < ppc_num_fprs; regi++) - regcache_raw_supply (regcache, - regcache_tdep->ppc_fp0_regnum + regi, - buf + 8 * regi); - - /* The FPSCR is stored in the low order word of the last - doubleword in the fpregset. */ - regcache_raw_supply (regcache, regcache_tdep->ppc_fpscr_regnum, - buf + 8 * 32 + 4); + return wordsize == 8 ? &ppc64_linux_gregset : &ppc32_linux_gregset; } -static struct regset ppc_linux_fpregset = { NULL, ppc_linux_supply_fpregset }; +const struct regset * +ppc_linux_fpregset (void) +{ + return &ppc32_linux_fpregset; +} static const struct regset * ppc_linux_regset_from_core_section (struct gdbarch *core_arch, @@ -735,7 +725,7 @@ ppc_linux_regset_from_core_section (struct gdbarch *core_arch, return &ppc64_linux_gregset; } if (strcmp (sect_name, ".reg2") == 0) - return &ppc_linux_fpregset; + return &ppc32_linux_fpregset; return NULL; } @@ -907,6 +897,11 @@ ppc_linux_init_abi (struct gdbarch_info info, /* NOTE: cagney/2005-01-25: True for both 32- and 64-bit. */ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT); + /* Handle PPC GNU/Linux 64-bit function pointers (which are really + function descriptors) and 32-bit secure PLT entries. */ + set_gdbarch_convert_from_func_ptr_addr + (gdbarch, ppc_linux_convert_from_func_ptr_addr); + if (tdep->wordsize == 4) { /* Until November 2001, gcc did not comply with the 32 bit SysV @@ -934,13 +929,8 @@ ppc_linux_init_abi (struct gdbarch_info info, if (tdep->wordsize == 8) { - /* Handle PPC64 GNU/Linux function pointers (which are really - function descriptors). */ - set_gdbarch_convert_from_func_ptr_addr - (gdbarch, ppc64_linux_convert_from_func_ptr_addr); - set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); - /* Shared library handling. */ + set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets);