From 99d0d5ed3ceb24909a1284178c9f62ba9427a1bd Mon Sep 17 00:00:00 2001 From: kettenis Date: Fri, 20 Jan 2006 23:37:06 +0000 Subject: [PATCH] * hppa-tdep.h (hppa_in_solib_call_trampoline) (hppa_skip_trampoline_code): New prototypes. * hppa-tdep.c (struct insn_pattern): New. (hppa_long_branch_stub, hppa_long_branch_pic_stub) (hppa_import_stub, hppa_import_pic_stub, hppa_plt_stub): Moved here from hppa-linux-tdep.c (HPPA_MAX_INSN_PATTERN_LEN): New define. (hppa_match_insns, hppa_match_insns_relaxed, hppa_in_dyncall) (hppa_in_solib_call_trampoline, hppa_skip_trampoline_code): New functions based on functions removed from hppa-linux-tdep.c. * hppa-linux-tdep.c (hppa_long_branch_stub) (hppa_long_branch_pic_stub, hppa_import_stub) (hppa_import_pic_stub, hppa_plt_stub): Moved to hppa-tdep.c. (insns_match_pattern_relaxed, hppa_linux_in_dyncall) (hppa_linux_in_solib_call_trampoline) (hppa_linux_skip_trampoline_code): Removed. (hppa_linux_init_abi): Set TDEP->in_solib_call_tranpoline to hppa_in_solib_call_trampoline and skip_trampoline_code to hppa_skip_trampoline_code. * hppabsd-tdep.c (hppabsd_init_abi): Set TDEP->in_solib_call_trampoline and skip_trampoline_code. --- gdb/ChangeLog | 24 ++++++ gdb/hppa-linux-tdep.c | 185 +----------------------------------------- gdb/hppa-tdep.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/hppa-tdep.h | 7 +- gdb/hppabsd-tdep.c | 4 +- 5 files changed, 252 insertions(+), 185 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c798db98b8..aa41f0ceb4 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,27 @@ +2006-01-20 Mark Kettenis + + * hppa-tdep.h (hppa_in_solib_call_trampoline) + (hppa_skip_trampoline_code): New prototypes. + * hppa-tdep.c (struct insn_pattern): New. + (hppa_long_branch_stub, hppa_long_branch_pic_stub) + (hppa_import_stub, hppa_import_pic_stub, hppa_plt_stub): Moved + here from hppa-linux-tdep.c + (HPPA_MAX_INSN_PATTERN_LEN): New define. + (hppa_match_insns, hppa_match_insns_relaxed, hppa_in_dyncall) + (hppa_in_solib_call_trampoline, hppa_skip_trampoline_code): New + functions based on functions removed from hppa-linux-tdep.c. + * hppa-linux-tdep.c (hppa_long_branch_stub) + (hppa_long_branch_pic_stub, hppa_import_stub) + (hppa_import_pic_stub, hppa_plt_stub): Moved to hppa-tdep.c. + (insns_match_pattern_relaxed, hppa_linux_in_dyncall) + (hppa_linux_in_solib_call_trampoline) + (hppa_linux_skip_trampoline_code): Removed. + (hppa_linux_init_abi): Set TDEP->in_solib_call_tranpoline to + hppa_in_solib_call_trampoline and skip_trampoline_code to + hppa_skip_trampoline_code. + * hppabsd-tdep.c (hppabsd_init_abi): Set + TDEP->in_solib_call_trampoline and skip_trampoline_code. + 2006-01-20 Jim Blandy * MAINTAINERS: Change my E-mail address. diff --git a/gdb/hppa-linux-tdep.c b/gdb/hppa-linux-tdep.c index 21f983bcfd..34199ae387 100644 --- a/gdb/hppa-linux-tdep.c +++ b/gdb/hppa-linux-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for GNU/Linux running on PA-RISC, for GDB. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -68,57 +68,6 @@ struct insn_pattern 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 }, @@ -162,133 +111,6 @@ insns_match_pattern (CORE_ADDR pc, return 1; } -/* The relaxed version of the insn matcher allows us to match from somewhere - inside the pattern, by looking backwards in the instruction scheme. */ -static int -insns_match_pattern_relaxed (CORE_ADDR pc, - struct insn_pattern *pattern, - unsigned int *insn) -{ - int pat_len = 0; - int offset; - - while (pattern[pat_len].mask) - pat_len++; - - for (offset = 0; offset < pat_len; offset++) - { - if (insns_match_pattern (pc - offset * 4, - pattern, insn)) - return 1; - } - - return 0; -} - -static int -hppa_linux_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; -} - -/* There are several kinds of "trampolines" that we need to deal with: - - long branch stubs: these are inserted by the linker when a branch - target is too far away for a branch insn to reach - - plt stubs: these should go into the .plt section, so are easy to find - - import stubs: used to call from object to shared lib or shared lib to - shared lib; these go in regular text sections. In fact the linker tries - to put them throughout the code because branches have limited reachability. - We use the same mechanism as ppc64 to recognize the stub insn patterns. - - $$dyncall: similar to hpux, hppa-linux uses $$dyncall for indirect function - calls. $$dyncall is exported by libgcc.a */ -static int -hppa_linux_in_solib_call_trampoline (CORE_ADDR pc, char *name) -{ - unsigned int insn[HPPA_MAX_INSN_PATTERN_LEN]; - int r; - struct unwind_table_entry *u; - - /* on hppa-linux, linker stubs have no unwind information. Since the pattern - matching for linker stubs can be quite slow, we try to avoid it if - we can. */ - u = find_unwind_entry (pc); - - r = in_plt_section (pc, name) - || hppa_linux_in_dyncall (pc) - || (u == NULL - && (insns_match_pattern_relaxed (pc, hppa_import_stub, insn) - || insns_match_pattern_relaxed (pc, hppa_import_pic_stub, insn) - || insns_match_pattern_relaxed (pc, hppa_long_branch_stub, insn) - || insns_match_pattern_relaxed (pc, hppa_long_branch_pic_stub, insn))); - - return r; -} - -static CORE_ADDR -hppa_linux_skip_trampoline_code (CORE_ADDR pc) -{ - unsigned int insn[HPPA_MAX_INSN_PATTERN_LEN]; - int dp_rel, pic_rel; - - /* dyncall handles both PLABELs and direct addresses */ - if (hppa_linux_in_dyncall (pc)) - { - pc = (CORE_ADDR) read_register (22); - - /* PLABELs have bit 30 set; if it's a PLABEL, then dereference it */ - if (pc & 0x2) - pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8); - - return pc; - } - - dp_rel = pic_rel = 0; - if ((dp_rel = insns_match_pattern (pc, hppa_import_stub, insn)) - || (pic_rel = insns_match_pattern (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 += (CORE_ADDR) read_register (27); - else - pc += (CORE_ADDR) read_register (19); - - /* fallthrough */ - } - - if (in_plt_section (pc, NULL)) - { - pc = (CORE_ADDR) read_memory_integer (pc, TARGET_PTR_BIT / 8); - - /* 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 (insns_match_pattern (pc, hppa_plt_stub, insn)) - { - /* this should point to the fixup routine */ - pc = (CORE_ADDR) read_memory_integer (pc + 8, TARGET_PTR_BIT / 8); - } - else - { - error (_("Cannot resolve plt stub at 0x%s."), - paddr_nz (pc)); - pc = 0; - } - } - } - - return pc; -} - /* Signal frames. */ /* (This is derived from MD_FALLBACK_FRAME_STATE_FOR in gcc.) @@ -600,9 +422,8 @@ hppa_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); - tdep->in_solib_call_trampoline = hppa_linux_in_solib_call_trampoline; - set_gdbarch_skip_trampoline_code - (gdbarch, hppa_linux_skip_trampoline_code); + tdep->in_solib_call_trampoline = hppa_in_solib_call_trampoline; + set_gdbarch_skip_trampoline_code (gdbarch, hppa_skip_trampoline_code); /* GNU/Linux uses the dynamic linker included in the GNU C Library. */ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c index eb7cef319f..425a6e8216 100644 --- a/gdb/hppa-tdep.c +++ b/gdb/hppa-tdep.c @@ -2737,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: diff --git a/gdb/hppa-tdep.h b/gdb/hppa-tdep.h index adaddae98d..4dbeaf53d4 100644 --- a/gdb/hppa-tdep.h +++ b/gdb/hppa-tdep.h @@ -1,6 +1,6 @@ /* Target-dependent code for the HP PA-RISC architecture. - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GDB. @@ -250,4 +250,7 @@ extern struct minimal_symbol * extern struct hppa_objfile_private * hppa_init_objfile_priv_data (struct objfile *objfile); -#endif /* HPPA_TDEP_H */ +extern int hppa_in_solib_call_trampoline (CORE_ADDR pc, char *name); +extern CORE_ADDR hppa_skip_trampoline_code (CORE_ADDR pc); + +#endif /* hppa-tdep.h */ diff --git a/gdb/hppabsd-tdep.c b/gdb/hppabsd-tdep.c index 7fb3c27a35..1c77bd9152 100644 --- a/gdb/hppabsd-tdep.c +++ b/gdb/hppabsd-tdep.c @@ -178,8 +178,10 @@ hppabsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) (gdbarch, hppabsd_regset_from_core_section); /* OpenBSD and NetBSD use ELF. */ - tdep->find_global_pointer = hppabsd_find_global_pointer; tdep->is_elf = 1; + tdep->find_global_pointer = hppabsd_find_global_pointer; + tdep->in_solib_call_trampoline = hppa_in_solib_call_trampoline; + set_gdbarch_skip_trampoline_code (gdbarch, hppa_skip_trampoline_code); /* OpenBSD and NetBSD use SVR4-style shared libraries. */ set_solib_svr4_fetch_link_map_offsets -- 2.11.0