X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fhppa-tdep.c;h=6a3ae47ba85285313f02408a8dc0981e41051be5;hb=806e23c026a7eee3db787352ff97cc4a1a41e357;hp=88eb1dc9decbb8f28a424049e5862d8eafeb0c9a;hpb=1ef7fcb5adf312dad7f75dff3a5f05c338b93b30;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index 88eb1dc9de..6a3ae47ba8 100644 --- a/gdb/hppa-tdep.c +++ b/gdb/hppa-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for the HP PA-RISC architecture. - Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, + Copyright (C) 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. @@ -21,8 +21,8 @@ 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ #include "defs.h" #include "bfd.h" @@ -897,6 +897,50 @@ hppa64_floating_p (const struct type *type) return 0; } +/* If CODE points to a function entry address, try to look up the corresponding + function descriptor and return its address instead. If CODE is not a + function entry address, then just return it unchanged. */ +static CORE_ADDR +hppa64_convert_code_addr_to_fptr (CORE_ADDR code) +{ + struct obj_section *sec, *opd; + + sec = find_pc_section (code); + + if (!sec) + return code; + + /* If CODE is in a data section, assume it's already a fptr. */ + if (!(sec->the_bfd_section->flags & SEC_CODE)) + return code; + + ALL_OBJFILE_OSECTIONS (sec->objfile, opd) + { + if (strcmp (opd->the_bfd_section->name, ".opd") == 0) + break; + } + + if (opd < sec->objfile->sections_end) + { + CORE_ADDR addr; + + for (addr = opd->addr; addr < opd->endaddr; addr += 2 * 8) + { + ULONGEST opdaddr; + char tmp[8]; + + if (target_read_memory (addr, tmp, sizeof (tmp))) + break; + opdaddr = extract_unsigned_integer (tmp, sizeof (tmp)); + + if (opdaddr == code) + return addr - 16; + } + } + + return code; +} + static CORE_ADDR hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, @@ -917,6 +961,7 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct type *type = value_type (arg); int len = TYPE_LENGTH (type); const bfd_byte *valbuf; + bfd_byte fptrbuf[8]; int regnum; /* "Each parameter begins on a 64-bit (8-byte) boundary." */ @@ -992,10 +1037,26 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } } + /* If we are passing a function pointer, make sure we pass a function + descriptor instead of the function entry address. */ + if (TYPE_CODE (type) == TYPE_CODE_PTR + && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC) + { + ULONGEST codeptr, fptr; + + codeptr = unpack_long (type, value_contents (arg)); + fptr = hppa64_convert_code_addr_to_fptr (codeptr); + store_unsigned_integer (fptrbuf, TYPE_LENGTH (type), fptr); + valbuf = fptrbuf; + } + else + { + valbuf = value_contents (arg); + } + /* Always store the argument in memory. */ - write_memory (sp + offset, value_contents (arg), len); + write_memory (sp + offset, valbuf, len); - valbuf = value_contents (arg); regnum = HPPA_ARG0_REGNUM - offset / 8; while (regnum > HPPA_ARG0_REGNUM - 8 && len > 0) { @@ -2676,6 +2737,223 @@ hppa_frame_prev_register_helper (struct frame_info *next_frame, } +/* An instruction to match. */ +struct insn_pattern +{ + unsigned int data; /* See if it matches this.... */ + unsigned int mask; /* ... with this mask. */ +}; + +/* See bfd/elf32-hppa.c */ +static struct insn_pattern hppa_long_branch_stub[] = { + /* ldil LR'xxx,%r1 */ + { 0x20200000, 0xffe00000 }, + /* be,n RR'xxx(%sr4,%r1) */ + { 0xe0202002, 0xffe02002 }, + { 0, 0 } +}; + +static struct insn_pattern hppa_long_branch_pic_stub[] = { + /* b,l .+8, %r1 */ + { 0xe8200000, 0xffe00000 }, + /* addil LR'xxx - ($PIC_pcrel$0 - 4), %r1 */ + { 0x28200000, 0xffe00000 }, + /* be,n RR'xxxx - ($PIC_pcrel$0 - 8)(%sr4, %r1) */ + { 0xe0202002, 0xffe02002 }, + { 0, 0 } +}; + +static struct insn_pattern hppa_import_stub[] = { + /* addil LR'xxx, %dp */ + { 0x2b600000, 0xffe00000 }, + /* ldw RR'xxx(%r1), %r21 */ + { 0x48350000, 0xffffb000 }, + /* bv %r0(%r21) */ + { 0xeaa0c000, 0xffffffff }, + /* ldw RR'xxx+4(%r1), %r19 */ + { 0x48330000, 0xffffb000 }, + { 0, 0 } +}; + +static struct insn_pattern hppa_import_pic_stub[] = { + /* addil LR'xxx,%r19 */ + { 0x2a600000, 0xffe00000 }, + /* ldw RR'xxx(%r1),%r21 */ + { 0x48350000, 0xffffb000 }, + /* bv %r0(%r21) */ + { 0xeaa0c000, 0xffffffff }, + /* ldw RR'xxx+4(%r1),%r19 */ + { 0x48330000, 0xffffb000 }, + { 0, 0 }, +}; + +static struct insn_pattern hppa_plt_stub[] = { + /* b,l 1b, %r20 - 1b is 3 insns before here */ + { 0xea9f1fdd, 0xffffffff }, + /* depi 0,31,2,%r20 */ + { 0xd6801c1e, 0xffffffff }, + { 0, 0 } +}; + +static struct insn_pattern hppa_sigtramp[] = { + /* ldi 0, %r25 or ldi 1, %r25 */ + { 0x34190000, 0xfffffffd }, + /* ldi __NR_rt_sigreturn, %r20 */ + { 0x3414015a, 0xffffffff }, + /* be,l 0x100(%sr2, %r0), %sr0, %r31 */ + { 0xe4008200, 0xffffffff }, + /* nop */ + { 0x08000240, 0xffffffff }, + { 0, 0 } +}; + +/* Maximum number of instructions on the patterns above. */ +#define HPPA_MAX_INSN_PATTERN_LEN 4 + +/* Return non-zero if the instructions at PC match the series + described in PATTERN, or zero otherwise. PATTERN is an array of + 'struct insn_pattern' objects, terminated by an entry whose mask is + zero. + + When the match is successful, fill INSN[i] with what PATTERN[i] + matched. */ + +static int +hppa_match_insns (CORE_ADDR pc, struct insn_pattern *pattern, + unsigned int *insn) +{ + CORE_ADDR npc = pc; + int i; + + for (i = 0; pattern[i].mask; i++) + { + gdb_byte buf[HPPA_INSN_SIZE]; + + deprecated_read_memory_nobpt (npc, buf, HPPA_INSN_SIZE); + insn[i] = extract_unsigned_integer (buf, HPPA_INSN_SIZE); + if ((insn[i] & pattern[i].mask) == pattern[i].data) + npc += 4; + else + return 0; + } + + return 1; +} + +/* This relaxed version of the insstruction matcher allows us to match + from somewhere inside the pattern, by looking backwards in the + instruction scheme. */ + +static int +hppa_match_insns_relaxed (CORE_ADDR pc, struct insn_pattern *pattern, + unsigned int *insn) +{ + int offset, len = 0; + + while (pattern[len].mask) + len++; + + for (offset = 0; offset < len; offset++) + if (hppa_match_insns (pc - offset * HPPA_INSN_SIZE, pattern, insn)) + return 1; + + return 0; +} + +static int +hppa_in_dyncall (CORE_ADDR pc) +{ + struct unwind_table_entry *u; + + u = find_unwind_entry (hppa_symbol_address ("$$dyncall")); + if (!u) + return 0; + + return (pc >= u->region_start && pc <= u->region_end); +} + +int +hppa_in_solib_call_trampoline (CORE_ADDR pc, char *name) +{ + unsigned int insn[HPPA_MAX_INSN_PATTERN_LEN]; + struct unwind_table_entry *u; + + if (in_plt_section (pc, name) || hppa_in_dyncall (pc)) + return 1; + + /* The GNU toolchain produces linker stubs without unwind + information. Since the pattern matching for linker stubs can be + quite slow, so bail out if we do have an unwind entry. */ + + u = find_unwind_entry (pc); + if (u != NULL) + return 0; + + return (hppa_match_insns_relaxed (pc, hppa_import_stub, insn) + || hppa_match_insns_relaxed (pc, hppa_import_pic_stub, insn) + || hppa_match_insns_relaxed (pc, hppa_long_branch_stub, insn) + || hppa_match_insns_relaxed (pc, hppa_long_branch_pic_stub, insn)); +} + +/* This code skips several kind of "trampolines" used on PA-RISC + systems: $$dyncall, import stubs and PLT stubs. */ + +CORE_ADDR +hppa_skip_trampoline_code (CORE_ADDR pc) +{ + unsigned int insn[HPPA_MAX_INSN_PATTERN_LEN]; + int dp_rel; + + /* $$dyncall handles both PLABELs and direct addresses. */ + if (hppa_in_dyncall (pc)) + { + pc = read_register (HPPA_R0_REGNUM + 22); + + /* PLABELs have bit 30 set; if it's a PLABEL, then dereference it. */ + if (pc & 0x2) + pc = read_memory_typed_address (pc & ~0x3, builtin_type_void_func_ptr); + + return pc; + } + + dp_rel = hppa_match_insns (pc, hppa_import_stub, insn); + if (dp_rel || hppa_match_insns (pc, hppa_import_pic_stub, insn)) + { + /* Extract the target address from the addil/ldw sequence. */ + pc = hppa_extract_21 (insn[0]) + hppa_extract_14 (insn[1]); + + if (dp_rel) + pc += read_register (HPPA_DP_REGNUM); + else + pc += read_register (HPPA_R0_REGNUM + 19); + + /* fallthrough */ + } + + if (in_plt_section (pc, NULL)) + { + pc = read_memory_typed_address (pc, builtin_type_void_func_ptr); + + /* If the PLT slot has not yet been resolved, the target will be + the PLT stub. */ + if (in_plt_section (pc, NULL)) + { + /* Sanity check: are we pointing to the PLT stub? */ + if (!hppa_match_insns (pc, hppa_plt_stub, insn)) + { + warning (_("Cannot resolve PLT stub at 0x%s."), paddr_nz (pc)); + return 0; + } + + /* This should point to the fixup routine. */ + pc = read_memory_typed_address (pc + 8, builtin_type_void_func_ptr); + } + } + + return pc; +} + + /* Here is a table of C type sizes on hppa with various compiles and options. I measured this on PA 9000/800 with HP-UX 11.11 and these compilers: