/* 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.
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"
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,
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." */
}
}
+ /* 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)
{
}
\f
+/* 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;
+}
+\f
+
/* 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: