* 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.
This commit is contained in:
Mark Kettenis 2006-01-20 23:37:07 +00:00
parent 80df1bbe05
commit 34f5501828
5 changed files with 252 additions and 185 deletions

View File

@ -1,3 +1,27 @@
2006-01-20 Mark Kettenis <kettenis@gnu.org>
* 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 <jimb@redhat.com>
* MAINTAINERS: Change my E-mail address.

View File

@ -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);

View File

@ -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:

View File

@ -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 */

View File

@ -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