X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fppc-linux-tdep.c;h=7f1318856f1ff33c475281471ae47cc941d639b6;hb=4e6d13a078772b6027840799e09c6453d84f166a;hp=e419e2e66c908ba023035165767916b6f4088126;hpb=00d5f93a8942ad81582852f5d06314866cd85287;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index e419e2e66c..7f1318856f 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -1,7 +1,7 @@ /* Target-dependent code for GDB, the GNU debugger. Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GDB. @@ -41,119 +41,18 @@ #include "features/rs6000/powerpc-32l.c" #include "features/rs6000/powerpc-altivec32l.c" +#include "features/rs6000/powerpc-vsx32l.c" +#include "features/rs6000/powerpc-isa205-32l.c" +#include "features/rs6000/powerpc-isa205-altivec32l.c" +#include "features/rs6000/powerpc-isa205-vsx32l.c" #include "features/rs6000/powerpc-64l.c" #include "features/rs6000/powerpc-altivec64l.c" +#include "features/rs6000/powerpc-vsx64l.c" +#include "features/rs6000/powerpc-isa205-64l.c" +#include "features/rs6000/powerpc-isa205-altivec64l.c" +#include "features/rs6000/powerpc-isa205-vsx64l.c" #include "features/rs6000/powerpc-e500l.c" -static CORE_ADDR -ppc_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) -{ - gdb_byte buf[4]; - struct obj_section *sect; - struct objfile *objfile; - unsigned long insn; - CORE_ADDR plt_start = 0; - CORE_ADDR symtab = 0; - CORE_ADDR strtab = 0; - int num_slots = -1; - int reloc_index = -1; - CORE_ADDR plt_table; - CORE_ADDR reloc; - CORE_ADDR sym; - long symidx; - char symname[1024]; - struct minimal_symbol *msymbol; - - /* Find the section pc is in; if not in .plt, try the default method. */ - sect = find_pc_section (pc); - if (!sect || strcmp (sect->the_bfd_section->name, ".plt") != 0) - return find_solib_trampoline_target (frame, pc); - - objfile = sect->objfile; - - /* Pick up the instruction at pc. It had better be of the - form - li r11, IDX - - where IDX is an index into the plt_table. */ - - if (target_read_memory (pc, buf, 4) != 0) - return 0; - insn = extract_unsigned_integer (buf, 4); - - if ((insn & 0xffff0000) != 0x39600000 /* li r11, VAL */ ) - return 0; - - reloc_index = (insn << 16) >> 16; - - /* Find the objfile that pc is in and obtain the information - necessary for finding the symbol name. */ - for (sect = objfile->sections; sect < objfile->sections_end; ++sect) - { - const char *secname = sect->the_bfd_section->name; - if (strcmp (secname, ".plt") == 0) - plt_start = sect->addr; - else if (strcmp (secname, ".rela.plt") == 0) - num_slots = ((int) sect->endaddr - (int) sect->addr) / 12; - else if (strcmp (secname, ".dynsym") == 0) - symtab = sect->addr; - else if (strcmp (secname, ".dynstr") == 0) - strtab = sect->addr; - } - - /* Make sure we have all the information we need. */ - if (plt_start == 0 || num_slots == -1 || symtab == 0 || strtab == 0) - return 0; - - /* Compute the value of the plt table */ - plt_table = plt_start + 72 + 8 * num_slots; - - /* Get address of the relocation entry (Elf32_Rela) */ - if (target_read_memory (plt_table + reloc_index, buf, 4) != 0) - return 0; - reloc = extract_unsigned_integer (buf, 4); - - sect = find_pc_section (reloc); - if (!sect) - return 0; - - if (strcmp (sect->the_bfd_section->name, ".text") == 0) - return reloc; - - /* Now get the r_info field which is the relocation type and symbol - index. */ - if (target_read_memory (reloc + 4, buf, 4) != 0) - return 0; - symidx = extract_unsigned_integer (buf, 4); - - /* Shift out the relocation type leaving just the symbol index */ - /* symidx = ELF32_R_SYM(symidx); */ - symidx = symidx >> 8; - - /* compute the address of the symbol */ - sym = symtab + symidx * 4; - - /* Fetch the string table index */ - if (target_read_memory (sym, buf, 4) != 0) - return 0; - symidx = extract_unsigned_integer (buf, 4); - - /* Fetch the string; we don't know how long it is. Is it possible - that the following will fail because we're trying to fetch too - much? */ - if (target_read_memory (strtab + symidx, (gdb_byte *) symname, - sizeof (symname)) != 0) - return 0; - - /* This might not work right if we have multiple symbols with the - same name; the only way to really get it right is to perform - the same sort of lookup as the dynamic linker. */ - msymbol = lookup_minimal_symbol_text (symname, NULL); - if (!msymbol) - return 0; - - return SYMBOL_VALUE_ADDRESS (msymbol); -} /* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint in much the same fashion as memory_remove_breakpoint in mem-break.c, @@ -440,7 +339,7 @@ ppc64_desc_entry_point (CORE_ADDR desc) /* Pattern for the standard linkage function. These are built by build_plt_stub in elf64-ppc.c, whose GLINK argument is always zero. */ -static struct insn_pattern ppc64_standard_linkage[] = +static struct insn_pattern ppc64_standard_linkage1[] = { /* addis r12, r2, */ { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, @@ -452,17 +351,16 @@ static struct insn_pattern ppc64_standard_linkage[] = { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, /* addis r12, r12, 1 */ - { insn_d (-1, -1, -1, -1), insn_d (15, 12, 2, 1), 1 }, + { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, /* ld r2, (r12) */ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, /* addis r12, r12, 1 */ - { insn_d (-1, -1, -1, -1), insn_d (15, 12, 2, 1), 1 }, + { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 }, /* mtctr r11 */ - { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), - 0 }, + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, /* ld r11, (r12) */ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, @@ -472,8 +370,68 @@ static struct insn_pattern ppc64_standard_linkage[] = { 0, 0, 0 } }; -#define PPC64_STANDARD_LINKAGE_LEN \ - (sizeof (ppc64_standard_linkage) / sizeof (ppc64_standard_linkage[0])) +#define PPC64_STANDARD_LINKAGE1_LEN \ + (sizeof (ppc64_standard_linkage1) / sizeof (ppc64_standard_linkage1[0])) + +static struct insn_pattern ppc64_standard_linkage2[] = + { + /* addis r12, r2, */ + { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, + + /* std r2, 40(r1) */ + { -1, insn_ds (62, 2, 1, 40, 0), 0 }, + + /* ld r11, (r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, + + /* addi r12, r12, */ + { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 }, + + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + + /* ld r2, (r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, + + /* ld r11, (r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; +#define PPC64_STANDARD_LINKAGE2_LEN \ + (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0])) + +static struct insn_pattern ppc64_standard_linkage3[] = + { + /* std r2, 40(r1) */ + { -1, insn_ds (62, 2, 1, 40, 0), 0 }, + + /* ld r11, (r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 }, + + /* addi r2, r2, */ + { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 }, + + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + + /* ld r11, (r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 }, + + /* ld r2, (r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, + + /* bctr */ + { -1, 0x4e800420, 0 }, + + { 0, 0, 0 } + }; +#define PPC64_STANDARD_LINKAGE3_LEN \ + (sizeof (ppc64_standard_linkage3) / sizeof (ppc64_standard_linkage3[0])) + /* When the dynamic linker is doing lazy symbol resolution, the first call to a function in another object will go like this: @@ -522,8 +480,8 @@ static struct insn_pattern ppc64_standard_linkage[] = standard linkage function will send them. (This doesn't deal with dynamic linker lazy symbol resolution stubs.) */ static CORE_ADDR -ppc64_standard_linkage_target (struct frame_info *frame, - CORE_ADDR pc, unsigned int *insn) +ppc64_standard_linkage1_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) { struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame)); @@ -539,20 +497,96 @@ ppc64_standard_linkage_target (struct frame_info *frame, return ppc64_desc_entry_point (desc); } +static struct core_regset_section ppc_linux_vsx_regset_sections[] = +{ + { ".reg", 268 }, + { ".reg2", 264 }, + { ".reg-ppc-vmx", 544 }, + { ".reg-ppc-vsx", 256 }, + { NULL, 0} +}; + +static struct core_regset_section ppc_linux_vmx_regset_sections[] = +{ + { ".reg", 268 }, + { ".reg2", 264 }, + { ".reg-ppc-vmx", 544 }, + { NULL, 0} +}; + +static struct core_regset_section ppc_linux_fp_regset_sections[] = +{ + { ".reg", 268 }, + { ".reg2", 264 }, + { NULL, 0} +}; + +static CORE_ADDR +ppc64_standard_linkage2_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame)); + + /* The address of the function descriptor this linkage function + references. */ + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + (insn_d_field (insn[0]) << 16) + + insn_ds_field (insn[2])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (desc); +} + +static CORE_ADDR +ppc64_standard_linkage3_target (struct frame_info *frame, + CORE_ADDR pc, unsigned int *insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame)); + + /* The address of the function descriptor this linkage function + references. */ + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + insn_ds_field (insn[1])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (desc); +} + /* Given that we've begun executing a call trampoline at PC, return the entry point of the function the trampoline will go to. */ static CORE_ADDR ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) { - unsigned int ppc64_standard_linkage_insn[PPC64_STANDARD_LINKAGE_LEN]; - - if (insns_match_pattern (pc, ppc64_standard_linkage, - ppc64_standard_linkage_insn)) - return ppc64_standard_linkage_target (frame, pc, - ppc64_standard_linkage_insn); + unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN]; + unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN]; + unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN]; + CORE_ADDR target; + + if (insns_match_pattern (pc, ppc64_standard_linkage1, + ppc64_standard_linkage1_insn)) + pc = ppc64_standard_linkage1_target (frame, pc, + ppc64_standard_linkage1_insn); + else if (insns_match_pattern (pc, ppc64_standard_linkage2, + ppc64_standard_linkage2_insn)) + pc = ppc64_standard_linkage2_target (frame, pc, + ppc64_standard_linkage2_insn); + else if (insns_match_pattern (pc, ppc64_standard_linkage3, + ppc64_standard_linkage3_insn)) + pc = ppc64_standard_linkage3_target (frame, pc, + ppc64_standard_linkage3_insn); else return 0; + + /* The PLT descriptor will either point to the already resolved target + address, or else to a glink stub. As the latter carry synthetic @plt + symbols, find_solib_trampoline_target should be able to resolve them. */ + target = find_solib_trampoline_target (frame, pc); + return target? target : pc; } @@ -591,7 +625,36 @@ ppc64_linux_convert_from_func_ptr_addr (struct gdbarch *gdbarch, /* 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); + { + /* There may be relocations that need to be applied to the .opd + section. Unfortunately, this function may be called at a time + where these relocations have not yet been performed -- this can + happen for example shortly after a library has been loaded with + dlopen, but ld.so has not yet applied the relocations. + + To cope with both the case where the relocation has been applied, + and the case where it has not yet been applied, we do *not* read + the (maybe) relocated value from target memory, but we instead + read the non-relocated value from the BFD, and apply the relocation + offset manually. + + This makes the assumption that all .opd entries are always relocated + by the same offset the section itself was relocated. This should + always be the case for GNU/Linux executables and shared libraries. + Note that other kind of object files (e.g. those added via + add-symbol-files) will currently never end up here anyway, as this + function accesses *target* sections only; only the main exec and + shared libraries are ever added to the target. */ + + gdb_byte buf[8]; + int res; + + res = bfd_get_section_contents (s->bfd, s->the_bfd_section, + &buf, addr - s->addr, 8); + if (res != 0) + return extract_unsigned_integer (buf, 8) + - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr; + } return addr; } @@ -731,6 +794,13 @@ static const struct regset ppc32_linux_vrregset = { NULL }; +static const struct regset ppc32_linux_vsxregset = { + &ppc32_linux_reg_offsets, + ppc_supply_vsxregset, + ppc_collect_vsxregset, + NULL +}; + const struct regset * ppc_linux_gregset (int wordsize) { @@ -759,6 +829,8 @@ ppc_linux_regset_from_core_section (struct gdbarch *core_arch, return &ppc32_linux_fpregset; if (strcmp (sect_name, ".reg-ppc-vmx") == 0) return &ppc32_linux_vrregset; + if (strcmp (sect_name, ".reg-ppc-vsx") == 0) + return &ppc32_linux_vsxregset; return NULL; } @@ -962,6 +1034,7 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch, bfd *abfd) { asection *altivec = bfd_get_section_by_name (abfd, ".reg-ppc-vmx"); + asection *vsx = bfd_get_section_by_name (abfd, ".reg-ppc-vsx"); asection *section = bfd_get_section_by_name (abfd, ".reg"); if (! section) return NULL; @@ -969,10 +1042,20 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch, switch (bfd_section_size (abfd, section)) { case 48 * 4: - return altivec? tdesc_powerpc_altivec32l : tdesc_powerpc_32l; + if (vsx) + return tdesc_powerpc_vsx32l; + else if (altivec) + return tdesc_powerpc_altivec32l; + else + return tdesc_powerpc_32l; case 48 * 8: - return altivec? tdesc_powerpc_altivec64l : tdesc_powerpc_64l; + if (vsx) + return tdesc_powerpc_vsx64l; + else if (altivec) + return tdesc_powerpc_altivec64l; + else + return tdesc_powerpc_64l; default: return NULL; @@ -1012,8 +1095,7 @@ ppc_linux_init_abi (struct gdbarch_info info, ppc_linux_memory_remove_breakpoint); /* Shared library handling. */ - set_gdbarch_skip_trampoline_code (gdbarch, - ppc_linux_skip_trampoline_code); + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); @@ -1024,15 +1106,6 @@ ppc_linux_init_abi (struct gdbarch_info info, if (tdep->wordsize == 8) { - /* Handle the 64-bit SVR4 minimal-symbol convention of using "FN" - for the descriptor and ".FN" for the entry-point -- a user - specifying "break FN" will unexpectedly end up with a breakpoint - on the descriptor and not the function. This architecture method - transforms any breakpoints on descriptors into breakpoints on the - corresponding entry point. */ - set_gdbarch_adjust_breakpoint_address - (gdbarch, ppc64_sysv_abi_adjust_breakpoint_address); - /* Handle PPC GNU/Linux 64-bit function pointers (which are really function descriptors). */ set_gdbarch_convert_from_func_ptr_addr @@ -1050,6 +1123,16 @@ ppc_linux_init_abi (struct gdbarch_info info, set_gdbarch_regset_from_core_section (gdbarch, ppc_linux_regset_from_core_section); set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description); + /* Supported register sections. */ + if (tdesc_find_feature (info.target_desc, + "org.gnu.gdb.power.vsx")) + set_gdbarch_core_regset_sections (gdbarch, ppc_linux_vsx_regset_sections); + else if (tdesc_find_feature (info.target_desc, + "org.gnu.gdb.power.altivec")) + set_gdbarch_core_regset_sections (gdbarch, ppc_linux_vmx_regset_sections); + else + set_gdbarch_core_regset_sections (gdbarch, ppc_linux_fp_regset_sections); + /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); @@ -1092,7 +1175,15 @@ _initialize_ppc_linux_tdep (void) /* Initialize the Linux target descriptions. */ initialize_tdesc_powerpc_32l (); initialize_tdesc_powerpc_altivec32l (); + initialize_tdesc_powerpc_vsx32l (); + initialize_tdesc_powerpc_isa205_32l (); + initialize_tdesc_powerpc_isa205_altivec32l (); + initialize_tdesc_powerpc_isa205_vsx32l (); initialize_tdesc_powerpc_64l (); initialize_tdesc_powerpc_altivec64l (); + initialize_tdesc_powerpc_vsx64l (); + initialize_tdesc_powerpc_isa205_64l (); + initialize_tdesc_powerpc_isa205_altivec64l (); + initialize_tdesc_powerpc_isa205_vsx64l (); initialize_tdesc_powerpc_e500l (); }