* 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,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);