-/* Target-dependent code for the HP PA architecture, for GDB.
+/* Target-dependent code for the HP PA-RISC architecture.
- Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
- Foundation, Inc.
+ Copyright (C) 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
+ Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
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 "frame.h"
#include "bfd.h"
#include "inferior.h"
-#include "value.h"
#include "regcache.h"
#include "completer.h"
-#include "language.h"
#include "osabi.h"
#include "gdb_assert.h"
-#include "infttrace.h"
+#include "gdb_stdint.h"
#include "arch-utils.h"
/* For argument passing to the inferior */
#include "symtab.h"
-#include "infcall.h"
#include "dis-asm.h"
#include "trad-frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
-#include "gdb_stat.h"
-#include "gdb_wait.h"
-
#include "gdbcore.h"
#include "gdbcmd.h"
-#include "target.h"
-#include "symfile.h"
+#include "gdbtypes.h"
#include "objfiles.h"
#include "hppa-tdep.h"
#define MASK_14 0x3fff
#define MASK_21 0x1fffff
-/* Define offsets into the call dummy for the _sr4export address.
- See comments related to CALL_DUMMY for more info. */
-#define SR4EXPORT_LDIL_OFFSET (HPPA_INSTRUCTION_SIZE * 12)
-#define SR4EXPORT_LDO_OFFSET (HPPA_INSTRUCTION_SIZE * 13)
-
/* Sizes (in bytes) of the native unwind entries. */
#define UNWIND_ENTRY_SIZE 16
#define STUB_UNWIND_ENTRY_SIZE 8
/* FIXME: brobecker 2002-11-07: We will likely be able to make the
following functions static, once we hppa is partially multiarched. */
int hppa_pc_requires_run_before_use (CORE_ADDR pc);
-int hppa_instruction_nullified (void);
-
-/* Handle 32/64-bit struct return conventions. */
-
-static enum return_value_convention
-hppa32_return_value (struct gdbarch *gdbarch,
- struct type *type, struct regcache *regcache,
- void *readbuf, const void *writebuf)
-{
- if (TYPE_LENGTH (type) <= 2 * 4)
- {
- /* The value always lives in the right hand end of the register
- (or register pair)? */
- int b;
- int reg = TYPE_CODE (type) == TYPE_CODE_FLT ? HPPA_FP4_REGNUM : 28;
- int part = TYPE_LENGTH (type) % 4;
- /* The left hand register contains only part of the value,
- transfer that first so that the rest can be xfered as entire
- 4-byte registers. */
- if (part > 0)
- {
- if (readbuf != NULL)
- regcache_cooked_read_part (regcache, reg, 4 - part,
- part, readbuf);
- if (writebuf != NULL)
- regcache_cooked_write_part (regcache, reg, 4 - part,
- part, writebuf);
- reg++;
- }
- /* Now transfer the remaining register values. */
- for (b = part; b < TYPE_LENGTH (type); b += 4)
- {
- if (readbuf != NULL)
- regcache_cooked_read (regcache, reg, (char *) readbuf + b);
- if (writebuf != NULL)
- regcache_cooked_write (regcache, reg, (const char *) writebuf + b);
- reg++;
- }
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- else
- return RETURN_VALUE_STRUCT_CONVENTION;
-}
-
-static enum return_value_convention
-hppa64_return_value (struct gdbarch *gdbarch,
- struct type *type, struct regcache *regcache,
- void *readbuf, const void *writebuf)
-{
- /* RM: Floats are returned in FR4R, doubles in FR4. Integral values
- are in r28, padded on the left. Aggregates less that 65 bits are
- in r28, right padded. Aggregates upto 128 bits are in r28 and
- r29, right padded. */
- if (TYPE_CODE (type) == TYPE_CODE_FLT
- && TYPE_LENGTH (type) <= 8)
- {
- /* Floats are right aligned? */
- int offset = register_size (gdbarch, HPPA_FP4_REGNUM) - TYPE_LENGTH (type);
- if (readbuf != NULL)
- regcache_cooked_read_part (regcache, HPPA_FP4_REGNUM, offset,
- TYPE_LENGTH (type), readbuf);
- if (writebuf != NULL)
- regcache_cooked_write_part (regcache, HPPA_FP4_REGNUM, offset,
- TYPE_LENGTH (type), writebuf);
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- else if (TYPE_LENGTH (type) <= 8 && is_integral_type (type))
- {
- /* Integrals are right aligned. */
- int offset = register_size (gdbarch, HPPA_FP4_REGNUM) - TYPE_LENGTH (type);
- if (readbuf != NULL)
- regcache_cooked_read_part (regcache, 28, offset,
- TYPE_LENGTH (type), readbuf);
- if (writebuf != NULL)
- regcache_cooked_write_part (regcache, 28, offset,
- TYPE_LENGTH (type), writebuf);
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- else if (TYPE_LENGTH (type) <= 2 * 8)
- {
- /* Composite values are left aligned. */
- int b;
- for (b = 0; b < TYPE_LENGTH (type); b += 8)
- {
- int part = min (8, TYPE_LENGTH (type) - b);
- if (readbuf != NULL)
- regcache_cooked_read_part (regcache, 28 + b / 8, 0, part,
- (char *) readbuf + b);
- if (writebuf != NULL)
- regcache_cooked_write_part (regcache, 28 + b / 8, 0, part,
- (const char *) writebuf + b);
- }
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- else
- return RETURN_VALUE_STRUCT_CONVENTION;
-}
/* Routines to extract various sized constants out of hppa
instructions. */
hppa_get_field (word, 11, 15) << 11 |
(word & 0x1) << 16, 17) << 2;
}
+
+CORE_ADDR
+hppa_symbol_address(const char *sym)
+{
+ struct minimal_symbol *minsym;
+
+ minsym = lookup_minimal_symbol (sym, NULL, NULL);
+ if (minsym)
+ return SYMBOL_VALUE_ADDRESS (minsym);
+ else
+ return (CORE_ADDR)-1;
+}
+
+struct hppa_objfile_private *
+hppa_init_objfile_priv_data (struct objfile *objfile)
+{
+ struct hppa_objfile_private *priv;
+
+ priv = (struct hppa_objfile_private *)
+ obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct hppa_objfile_private));
+ set_objfile_data (objfile, hppa_objfile_priv_data, priv);
+ memset (priv, 0, sizeof (*priv));
+
+ return priv;
+}
\f
/* Compare the start address for two unwind entries returning 1 if
text_offset = low_text_segment_address;
}
+ else if (gdbarch_tdep (current_gdbarch)->solib_get_text_base)
+ {
+ text_offset = gdbarch_tdep (current_gdbarch)->solib_get_text_base (objfile);
+ }
bfd_get_section_contents (objfile->obfd, section, buf, 0, size);
table[i].Millicode = (tmp >> 30) & 0x1;
table[i].Millicode_save_sr0 = (tmp >> 29) & 0x1;
table[i].Region_description = (tmp >> 27) & 0x3;
- table[i].reserved1 = (tmp >> 26) & 0x1;
+ table[i].reserved = (tmp >> 26) & 0x1;
table[i].Entry_SR = (tmp >> 25) & 0x1;
table[i].Entry_FR = (tmp >> 21) & 0xf;
table[i].Entry_GR = (tmp >> 16) & 0x1f;
table[i].Frame_Extension_Millicode = (tmp >> 12) & 0x1;
table[i].Stack_Overflow_Check = (tmp >> 11) & 0x1;
table[i].Two_Instruction_SP_Increment = (tmp >> 10) & 0x1;
- table[i].Ada_Region = (tmp >> 9) & 0x1;
+ table[i].sr4export = (tmp >> 9) & 0x1;
table[i].cxx_info = (tmp >> 8) & 0x1;
table[i].cxx_try_catch = (tmp >> 7) & 0x1;
table[i].sched_entry_seq = (tmp >> 6) & 0x1;
- table[i].reserved2 = (tmp >> 5) & 0x1;
+ table[i].reserved1 = (tmp >> 5) & 0x1;
table[i].Save_SP = (tmp >> 4) & 0x1;
table[i].Save_RP = (tmp >> 3) & 0x1;
table[i].Save_MRP_in_frame = (tmp >> 2) & 0x1;
- table[i].extn_ptr_defined = (tmp >> 1) & 0x1;
+ table[i].save_r19 = (tmp >> 1) & 0x1;
table[i].Cleanup_defined = tmp & 0x1;
tmp = bfd_get_32 (objfile->obfd, (bfd_byte *) buf);
buf += 4;
table[i].MPE_XL_interrupt_marker = (tmp >> 31) & 0x1;
table[i].HP_UX_interrupt_marker = (tmp >> 30) & 0x1;
table[i].Large_frame = (tmp >> 29) & 0x1;
- table[i].Pseudo_SP_Set = (tmp >> 28) & 0x1;
- table[i].reserved4 = (tmp >> 27) & 0x1;
+ table[i].alloca_frame = (tmp >> 28) & 0x1;
+ table[i].reserved2 = (tmp >> 27) & 0x1;
table[i].Total_frame_size = tmp & 0x7ffffff;
/* Stub unwinds are handled elsewhere. */
}
/* Now compute the size of the stub unwinds. Note the ELF tools do not
- use stub unwinds at the curren time. */
+ use stub unwinds at the current time. */
stub_unwind_sec = bfd_get_section_by_name (objfile->obfd, "$UNWIND_END$");
if (stub_unwind_sec)
obj_private = (struct hppa_objfile_private *)
objfile_data (objfile, hppa_objfile_priv_data);
if (obj_private == NULL)
- {
- obj_private = (struct hppa_objfile_private *)
- obstack_alloc (&objfile->objfile_obstack,
- sizeof (struct hppa_objfile_private));
- set_objfile_data (objfile, hppa_objfile_priv_data, obj_private);
- obj_private->unwind_info = NULL;
- obj_private->so_info = NULL;
- obj_private->dp = 0;
- }
+ obj_private = hppa_init_objfile_priv_data (objfile);
+
obj_private->unwind_info = ui;
}
read_unwind_info (objfile);
priv = objfile_data (objfile, hppa_objfile_priv_data);
if (priv == NULL)
- error ("Internal error reading unwind information.");
+ error (_("Internal error reading unwind information."));
ui = ((struct hppa_objfile_private *) priv)->unwind_info;
}
{
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, "0x%s (cached) }\n",
- paddr_nz ((CORE_ADDR) ui->cache));
+ paddr_nz ((uintptr_t) ui->cache));
return ui->cache;
}
ui->cache = &ui->table[middle];
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, "0x%s }\n",
- paddr_nz ((CORE_ADDR) ui->cache));
+ paddr_nz ((uintptr_t) ui->cache));
return &ui->table[middle];
}
return NULL;
}
+/* The epilogue is defined here as the area either on the `bv' instruction
+ itself or an instruction which destroys the function's stack frame.
+
+ We do not assume that the epilogue is at the end of a function as we can
+ also have return sequences in the middle of a function. */
+static int
+hppa_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ unsigned long status;
+ unsigned int inst;
+ char buf[4];
+ int off;
+
+ status = read_memory_nobpt (pc, buf, 4);
+ if (status != 0)
+ return 0;
+
+ inst = extract_unsigned_integer (buf, 4);
+
+ /* The most common way to perform a stack adjustment ldo X(sp),sp
+ We are destroying a stack frame if the offset is negative. */
+ if ((inst & 0xffffc000) == 0x37de0000
+ && hppa_extract_14 (inst) < 0)
+ return 1;
+
+ /* ldw,mb D(sp),X or ldd,mb D(sp),X */
+ if (((inst & 0x0fc010e0) == 0x0fc010e0
+ || (inst & 0x0fc010e0) == 0x0fc010e0)
+ && hppa_extract_14 (inst) < 0)
+ return 1;
+
+ /* bv %r0(%rp) or bv,n %r0(%rp) */
+ if (inst == 0xe840c000 || inst == 0xe840c002)
+ return 1;
+
+ return 0;
+}
+
static const unsigned char *
hppa_breakpoint_from_pc (CORE_ADDR *pc, int *len)
{
/* Return the name of a register. */
-const char *
+static const char *
hppa32_register_name (int i)
{
static char *names[] = {
return names[i];
}
-const char *
+static const char *
hppa64_register_name (int i)
{
static char *names[] = {
return names[i];
}
+static int
+hppa64_dwarf_reg_to_regnum (int reg)
+{
+ /* r0-r31 and sar map one-to-one. */
+ if (reg <= 32)
+ return reg;
+
+ /* fr4-fr31 are mapped from 72 in steps of 2. */
+ if (reg >= 72 || reg < 72 + 28 * 2)
+ return HPPA64_FP4_REGNUM + (reg - 72) / 2;
+
+ error ("Invalid DWARF register num %d.", reg);
+ return -1;
+}
+
/* This function pushes a stack frame with arguments as part of the
inferior function calling mechanism.
We simply allocate the appropriate amount of stack space and put
arguments into their proper slots. */
-CORE_ADDR
-hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+static CORE_ADDR
+hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
/* Two passes. First pass computes the location of everything,
second pass writes the bytes out. */
int write_pass;
+
+ /* Global pointer (r19) of the function we are trying to call. */
+ CORE_ADDR gp;
+
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
for (write_pass = 0; write_pass < 2; write_pass++)
{
CORE_ADDR struct_ptr = 0;
for (i = 0; i < nargs; i++)
{
struct value *arg = args[i];
- struct type *type = check_typedef (VALUE_TYPE (arg));
+ struct type *type = check_typedef (value_type (arg));
/* The corresponding parameter that is pushed onto the
stack, and [possibly] passed in a register. */
char param_val[8];
param_len = 4;
struct_ptr += align_up (TYPE_LENGTH (type), 8);
if (write_pass)
- write_memory (struct_end - struct_ptr, VALUE_CONTENTS (arg),
+ write_memory (struct_end - struct_ptr, value_contents (arg),
TYPE_LENGTH (type));
store_unsigned_integer (param_val, 4, struct_end - struct_ptr);
}
param_len = align_up (TYPE_LENGTH (type), 4);
store_unsigned_integer (param_val, param_len,
unpack_long (type,
- VALUE_CONTENTS (arg)));
+ value_contents (arg)));
}
else if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
/* Floating point value store, right aligned. */
param_len = align_up (TYPE_LENGTH (type), 4);
- memcpy (param_val, VALUE_CONTENTS (arg), param_len);
+ memcpy (param_val, value_contents (arg), param_len);
}
else
{
/* Small struct value are stored right-aligned. */
memcpy (param_val + param_len - TYPE_LENGTH (type),
- VALUE_CONTENTS (arg), TYPE_LENGTH (type));
+ value_contents (arg), TYPE_LENGTH (type));
/* Structures of size 5, 6 and 7 bytes are special in that
the higher-ordered word is stored in the lower-ordered
argument, and even though it is a 8-byte quantity the
registers need not be 8-byte aligned. */
- if (param_len > 4)
+ if (param_len > 4 && param_len < 8)
small_struct = 1;
}
/* If a structure has to be returned, set up register 28 to hold its
address */
if (struct_return)
- write_register (28, struct_addr);
+ regcache_cooked_write_unsigned (regcache, 28, struct_addr);
+
+ gp = tdep->find_global_pointer (function);
+
+ if (gp != 0)
+ regcache_cooked_write_unsigned (regcache, 19, gp);
/* Set the return address. */
- regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
+ if (!gdbarch_push_dummy_code_p (gdbarch))
+ regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
/* Update the Stack Pointer. */
regcache_cooked_write_unsigned (regcache, HPPA_SP_REGNUM, param_end);
return param_end;
}
-/* This function pushes a stack frame with arguments as part of the
- inferior function calling mechanism.
+/* The 64-bit PA-RISC calling conventions are documented in "64-Bit
+ Runtime Architecture for PA-RISC 2.0", which is distributed as part
+ as of the HP-UX Software Transition Kit (STK). This implementation
+ is based on version 3.3, dated October 6, 1997. */
- This is the version for the PA64, in which later arguments appear
- at higher addresses. (The stack always grows towards higher
- addresses.)
+/* Check whether TYPE is an "Integral or Pointer Scalar Type". */
- We simply allocate the appropriate amount of stack space and put
- arguments into their proper slots.
+static int
+hppa64_integral_or_pointer_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_RANGE:
+ {
+ int len = TYPE_LENGTH (type);
+ return (len == 1 || len == 2 || len == 4 || len == 8);
+ }
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_REF:
+ return (TYPE_LENGTH (type) == 8);
+ default:
+ break;
+ }
- This ABI also requires that the caller provide an argument pointer
- to the callee, so we do that too. */
-
-CORE_ADDR
-hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+ return 0;
+}
+
+/* Check whether TYPE is a "Floating Scalar Type". */
+
+static int
+hppa64_floating_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_FLT:
+ {
+ int len = TYPE_LENGTH (type);
+ return (len == 4 || len == 8 || len == 16);
+ }
+ default:
+ break;
+ }
+
+ 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,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
- /* NOTE: cagney/2004-02-27: This is a guess - its implemented by
- reverse engineering testsuite failures. */
-
- /* Stack base address at which any pass-by-reference parameters are
- stored. */
- CORE_ADDR struct_end = 0;
- /* Stack base address at which the first parameter is stored. */
- CORE_ADDR param_end = 0;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int i, offset = 0;
+ CORE_ADDR gp;
- /* The inner most end of the stack after all the parameters have
- been pushed. */
- CORE_ADDR new_sp = 0;
+ /* "The outgoing parameter area [...] must be aligned at a 16-byte
+ boundary." */
+ sp = align_up (sp, 16);
- /* Two passes. First pass computes the location of everything,
- second pass writes the bytes out. */
- int write_pass;
- for (write_pass = 0; write_pass < 2; write_pass++)
+ for (i = 0; i < nargs; i++)
{
- CORE_ADDR struct_ptr = 0;
- CORE_ADDR param_ptr = 0;
- int i;
- for (i = 0; i < nargs; i++)
+ struct value *arg = args[i];
+ 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." */
+ offset = align_up (offset, 8);
+
+ if (hppa64_integral_or_pointer_p (type))
{
- struct value *arg = args[i];
- struct type *type = check_typedef (VALUE_TYPE (arg));
- if ((TYPE_CODE (type) == TYPE_CODE_INT
- || TYPE_CODE (type) == TYPE_CODE_ENUM)
- && TYPE_LENGTH (type) <= 8)
+ /* "Integral scalar parameters smaller than 64 bits are
+ padded on the left (i.e., the value is in the
+ least-significant bits of the 64-bit storage unit, and
+ the high-order bits are undefined)." Therefore we can
+ safely sign-extend them. */
+ if (len < 8)
{
- /* Integer value store, right aligned. "unpack_long"
- takes care of any sign-extension problems. */
- param_ptr += 8;
- if (write_pass)
- {
- ULONGEST val = unpack_long (type, VALUE_CONTENTS (arg));
- int reg = 27 - param_ptr / 8;
- write_memory_unsigned_integer (param_end - param_ptr,
- val, 8);
- if (reg >= 19)
- regcache_cooked_write_unsigned (regcache, reg, val);
- }
+ arg = value_cast (builtin_type_int64, arg);
+ len = 8;
+ }
+ }
+ else if (hppa64_floating_p (type))
+ {
+ if (len > 8)
+ {
+ /* "Quad-precision (128-bit) floating-point scalar
+ parameters are aligned on a 16-byte boundary." */
+ offset = align_up (offset, 16);
+
+ /* "Double-extended- and quad-precision floating-point
+ parameters within the first 64 bytes of the parameter
+ list are always passed in general registers." */
}
else
{
- /* Small struct value, store left aligned? */
- int reg;
- if (TYPE_LENGTH (type) > 8)
+ if (len == 4)
{
- param_ptr = align_up (param_ptr, 16);
- reg = 26 - param_ptr / 8;
- param_ptr += align_up (TYPE_LENGTH (type), 16);
+ /* "Single-precision (32-bit) floating-point scalar
+ parameters are padded on the left with 32 bits of
+ garbage (i.e., the floating-point value is in the
+ least-significant 32 bits of a 64-bit storage
+ unit)." */
+ offset += 4;
}
- else
- {
- param_ptr = align_up (param_ptr, 8);
- reg = 26 - param_ptr / 8;
- param_ptr += align_up (TYPE_LENGTH (type), 8);
- }
- if (write_pass)
+
+ /* "Single- and double-precision floating-point
+ parameters in this area are passed according to the
+ available formal parameter information in a function
+ prototype. [...] If no prototype is in scope,
+ floating-point parameters must be passed both in the
+ corresponding general registers and in the
+ corresponding floating-point registers." */
+ regnum = HPPA64_FP4_REGNUM + offset / 8;
+
+ if (regnum < HPPA64_FP4_REGNUM + 8)
{
- int byte;
- write_memory (param_end - param_ptr, VALUE_CONTENTS (arg),
- TYPE_LENGTH (type));
- for (byte = 0; byte < TYPE_LENGTH (type); byte += 8)
- {
- if (reg >= 19)
- {
- int len = min (8, TYPE_LENGTH (type) - byte);
- regcache_cooked_write_part (regcache, reg, 0, len,
- VALUE_CONTENTS (arg) + byte);
- }
- reg--;
- }
+ /* "Single-precision floating-point parameters, when
+ passed in floating-point registers, are passed in
+ the right halves of the floating point registers;
+ the left halves are unused." */
+ regcache_cooked_write_part (regcache, regnum, offset % 8,
+ len, value_contents (arg));
}
}
}
- /* Update the various stack pointers. */
- if (!write_pass)
+ else
{
- struct_end = sp + struct_ptr;
- /* PARAM_PTR already accounts for all the arguments passed
- by the user. However, the ABI mandates minimum stack
- space allocations for outgoing arguments. The ABI also
- mandates minimum stack alignments which we must
- preserve. */
- param_end = struct_end + max (align_up (param_ptr, 16), 64);
+ if (len > 8)
+ {
+ /* "Aggregates larger than 8 bytes are aligned on a
+ 16-byte boundary, possibly leaving an unused argument
+ slot, which is filled with garbage. If necessary,
+ they are padded on the right (with garbage), to a
+ multiple of 8 bytes." */
+ offset = align_up (offset, 16);
+ }
+ }
+
+ /* 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, valbuf, len);
+
+ regnum = HPPA_ARG0_REGNUM - offset / 8;
+ while (regnum > HPPA_ARG0_REGNUM - 8 && len > 0)
+ {
+ regcache_cooked_write_part (regcache, regnum,
+ offset % 8, min (len, 8), valbuf);
+ offset += min (len, 8);
+ valbuf += min (len, 8);
+ len -= min (len, 8);
+ regnum--;
}
+
+ offset += len;
}
- /* If a structure has to be returned, set up register 28 to hold its
- address */
+ /* Set up GR29 (%ret1) to hold the argument pointer (ap). */
+ regcache_cooked_write_unsigned (regcache, HPPA_RET1_REGNUM, sp + 64);
+
+ /* Allocate the outgoing parameter area. Make sure the outgoing
+ parameter area is multiple of 16 bytes in length. */
+ sp += max (align_up (offset, 16), 64);
+
+ /* Allocate 32-bytes of scratch space. The documentation doesn't
+ mention this, but it seems to be needed. */
+ sp += 32;
+
+ /* Allocate the frame marker area. */
+ sp += 16;
+
+ /* If a structure has to be returned, set up GR 28 (%ret0) to hold
+ its address. */
if (struct_return)
- write_register (28, struct_addr);
+ regcache_cooked_write_unsigned (regcache, HPPA_RET0_REGNUM, struct_addr);
- /* Set the return address. */
- regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
+ /* Set up GR27 (%dp) to hold the global pointer (gp). */
+ gp = tdep->find_global_pointer (function);
+ if (gp != 0)
+ regcache_cooked_write_unsigned (regcache, HPPA_DP_REGNUM, gp);
- /* Update the Stack Pointer. */
- regcache_cooked_write_unsigned (regcache, HPPA_SP_REGNUM, param_end + 64);
+ /* Set up GR2 (%rp) to hold the return pointer (rp). */
+ if (!gdbarch_push_dummy_code_p (gdbarch))
+ regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
+
+ /* Set up GR30 to hold the stack pointer (sp). */
+ regcache_cooked_write_unsigned (regcache, HPPA_SP_REGNUM, sp);
- /* The stack will have 32 bytes of additional space for a frame marker. */
- return param_end + 64;
+ return sp;
+}
+\f
+
+/* Handle 32/64-bit struct return conventions. */
+
+static enum return_value_convention
+hppa32_return_value (struct gdbarch *gdbarch,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (TYPE_LENGTH (type) <= 2 * 4)
+ {
+ /* The value always lives in the right hand end of the register
+ (or register pair)? */
+ int b;
+ int reg = TYPE_CODE (type) == TYPE_CODE_FLT ? HPPA_FP4_REGNUM : 28;
+ int part = TYPE_LENGTH (type) % 4;
+ /* The left hand register contains only part of the value,
+ transfer that first so that the rest can be xfered as entire
+ 4-byte registers. */
+ if (part > 0)
+ {
+ if (readbuf != NULL)
+ regcache_cooked_read_part (regcache, reg, 4 - part,
+ part, readbuf);
+ if (writebuf != NULL)
+ regcache_cooked_write_part (regcache, reg, 4 - part,
+ part, writebuf);
+ reg++;
+ }
+ /* Now transfer the remaining register values. */
+ for (b = part; b < TYPE_LENGTH (type); b += 4)
+ {
+ if (readbuf != NULL)
+ regcache_cooked_read (regcache, reg, readbuf + b);
+ if (writebuf != NULL)
+ regcache_cooked_write (regcache, reg, writebuf + b);
+ reg++;
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+ else
+ return RETURN_VALUE_STRUCT_CONVENTION;
+}
+
+static enum return_value_convention
+hppa64_return_value (struct gdbarch *gdbarch,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ int len = TYPE_LENGTH (type);
+ int regnum, offset;
+
+ if (len > 16)
+ {
+ /* All return values larget than 128 bits must be aggregate
+ return values. */
+ gdb_assert (!hppa64_integral_or_pointer_p (type));
+ gdb_assert (!hppa64_floating_p (type));
+
+ /* "Aggregate return values larger than 128 bits are returned in
+ a buffer allocated by the caller. The address of the buffer
+ must be passed in GR 28." */
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ }
+
+ if (hppa64_integral_or_pointer_p (type))
+ {
+ /* "Integral return values are returned in GR 28. Values
+ smaller than 64 bits are padded on the left (with garbage)." */
+ regnum = HPPA_RET0_REGNUM;
+ offset = 8 - len;
+ }
+ else if (hppa64_floating_p (type))
+ {
+ if (len > 8)
+ {
+ /* "Double-extended- and quad-precision floating-point
+ values are returned in GRs 28 and 29. The sign,
+ exponent, and most-significant bits of the mantissa are
+ returned in GR 28; the least-significant bits of the
+ mantissa are passed in GR 29. For double-extended
+ precision values, GR 29 is padded on the right with 48
+ bits of garbage." */
+ regnum = HPPA_RET0_REGNUM;
+ offset = 0;
+ }
+ else
+ {
+ /* "Single-precision and double-precision floating-point
+ return values are returned in FR 4R (single precision) or
+ FR 4 (double-precision)." */
+ regnum = HPPA64_FP4_REGNUM;
+ offset = 8 - len;
+ }
+ }
+ else
+ {
+ /* "Aggregate return values up to 64 bits in size are returned
+ in GR 28. Aggregates smaller than 64 bits are left aligned
+ in the register; the pad bits on the right are undefined."
+
+ "Aggregate return values between 65 and 128 bits are returned
+ in GRs 28 and 29. The first 64 bits are placed in GR 28, and
+ the remaining bits are placed, left aligned, in GR 29. The
+ pad bits on the right of GR 29 (if any) are undefined." */
+ regnum = HPPA_RET0_REGNUM;
+ offset = 0;
+ }
+
+ if (readbuf)
+ {
+ while (len > 0)
+ {
+ regcache_cooked_read_part (regcache, regnum, offset,
+ min (len, 8), readbuf);
+ readbuf += min (len, 8);
+ len -= min (len, 8);
+ regnum++;
+ }
+ }
+
+ if (writebuf)
+ {
+ while (len > 0)
+ {
+ regcache_cooked_write_part (regcache, regnum, offset,
+ min (len, 8), writebuf);
+ writebuf += min (len, 8);
+ len -= min (len, 8);
+ regnum++;
+ }
+ }
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+\f
+
+static CORE_ADDR
+hppa32_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
+ struct target_ops *targ)
+{
+ if (addr & 2)
+ {
+ CORE_ADDR plabel = addr & ~3;
+ return read_memory_typed_address (plabel, builtin_type_void_func_ptr);
+ }
+
+ return addr;
}
static CORE_ADDR
return align_up (addr, 16);
}
-
-/* Get the PC from %r31 if currently in a syscall. Also mask out privilege
- bits. */
-
-static CORE_ADDR
-hppa_target_read_pc (ptid_t ptid)
+CORE_ADDR
+hppa_read_pc (struct regcache *regcache)
{
- int flags = read_register_pid (HPPA_FLAGS_REGNUM, ptid);
+ ULONGEST ipsw;
+ ULONGEST pc;
- /* The following test does not belong here. It is OS-specific, and belongs
- in native code. */
- /* Test SS_INSYSCALL */
- if (flags & 2)
- return read_register_pid (31, ptid) & ~0x3;
+ regcache_cooked_read_unsigned (regcache, HPPA_IPSW_REGNUM, &ipsw);
+ regcache_cooked_read_unsigned (regcache, HPPA_PCOQ_HEAD_REGNUM, &pc);
- return read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid) & ~0x3;
-}
+ /* If the current instruction is nullified, then we are effectively
+ still executing the previous instruction. Pretend we are still
+ there. This is needed when single stepping; if the nullified
+ instruction is on a different line, we don't want GDB to think
+ we've stepped onto that line. */
+ if (ipsw & 0x00200000)
+ pc -= 4;
-/* Write out the PC. If currently in a syscall, then also write the new
- PC value into %r31. */
+ return pc & ~0x3;
+}
-static void
-hppa_target_write_pc (CORE_ADDR v, ptid_t ptid)
+void
+hppa_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
- int flags = read_register_pid (HPPA_FLAGS_REGNUM, ptid);
-
- /* The following test does not belong here. It is OS-specific, and belongs
- in native code. */
- /* If in a syscall, then set %r31. Also make sure to get the
- privilege bits set correctly. */
- /* Test SS_INSYSCALL */
- if (flags & 2)
- write_register_pid (31, v | 0x3, ptid);
-
- write_register_pid (HPPA_PCOQ_HEAD_REGNUM, v, ptid);
- write_register_pid (HPPA_PCOQ_TAIL_REGNUM, v + 4, ptid);
+ regcache_cooked_write_unsigned (regcache, HPPA_PCOQ_HEAD_REGNUM, pc);
+ regcache_cooked_write_unsigned (regcache, HPPA_PCOQ_TAIL_REGNUM, pc + 4);
}
/* return the alignment of a type in bytes. Structures have the maximum
if ((inst & 0xffe00008) == 0x73c00008)
return (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
- /* addil high21,%r1; ldo low11,(%r1),%r30)
+ /* addil high21,%r30; ldo low11,(%r1),%r30)
save high bits in save_high21 for later use. */
- if ((inst & 0xffe00000) == 0x28200000)
+ if ((inst & 0xffe00000) == 0x2bc00000)
{
save_high21 = hppa_extract_21 (inst);
return 0;
be in the prologue. */
-CORE_ADDR
-skip_prologue_hard_way (CORE_ADDR pc)
+static CORE_ADDR
+skip_prologue_hard_way (CORE_ADDR pc, int stop_before_branch)
{
char buf[4];
CORE_ADDR orig_pc = pc;
unsigned long inst, stack_remaining, save_gr, save_fr, save_rp, save_sp;
unsigned long args_stored, status, i, restart_gr, restart_fr;
struct unwind_table_entry *u;
+ int final_iteration;
restart_gr = 0;
restart_fr = 0;
save_fr |= (1 << i);
save_fr &= ~restart_fr;
+ final_iteration = 0;
+
/* Loop until we find everything of interest or hit a branch.
For unoptimized GCC code and for any HP CC code this will never ever
/* There are limited ways to store the return pointer into the
stack. */
- if (inst == 0x6bc23fd9 || inst == 0x0fc212c1)
+ if (inst == 0x6bc23fd9 || inst == 0x0fc212c1 || inst == 0x73c23fe1)
save_rp = 0;
/* These are the only ways we save SP into the stack. At this time
FIXME. Can still die if we have a mix of GR and FR argument
stores! */
- if (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
+ if (reg_num >= (gdbarch_ptr_bit (current_gdbarch) == 64 ? 19 : 23)
+ && reg_num <= 26)
{
- while (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
+ while (reg_num >= (gdbarch_ptr_bit (current_gdbarch) == 64 ? 19 : 23)
+ && reg_num <= 26)
{
pc += 4;
status = read_memory_nobpt (pc, buf, 4);
save. */
if ((inst & 0xfc000000) == 0x34000000
&& inst_saves_fr (next_inst) >= 4
- && inst_saves_fr (next_inst) <= (TARGET_PTR_BIT == 64 ? 11 : 7))
+ && inst_saves_fr (next_inst)
+ <= (gdbarch_ptr_bit (current_gdbarch) == 64 ? 11 : 7))
{
/* So we drop into the code below in a reasonable state. */
reg_num = inst_saves_fr (next_inst);
This is a kludge as on the HP compiler sets this bit and it
never does prologue scheduling. So once we see one, skip past
all of them. */
- if (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
+ if (reg_num >= 4
+ && reg_num <= (gdbarch_ptr_bit (current_gdbarch) == 64 ? 11 : 7))
{
- while (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
+ while (reg_num >= 4
+ && reg_num
+ <= (gdbarch_ptr_bit (current_gdbarch) == 64 ? 11 : 7))
{
pc += 8;
status = read_memory_nobpt (pc, buf, 4);
/* Quit if we hit any kind of branch. This can happen if a prologue
instruction is in the delay slot of the first call/branch. */
- if (is_branch (inst))
+ if (is_branch (inst) && stop_before_branch)
break;
/* What a crock. The HP compilers set args_stored even if no
/* Bump the PC. */
pc += 4;
+
+ /* !stop_before_branch, so also look at the insn in the delay slot
+ of the branch. */
+ if (final_iteration)
+ break;
+ if (is_branch (inst))
+ final_iteration = 1;
}
/* We've got a tenative location for the end of the prologue. However
/* To skip prologues, I use this predicate. Returns either PC itself
if the code at PC does not look like a function prologue; otherwise
- returns an address that (if we're lucky) follows the prologue. If
- LENIENT, then we must skip everything which is involved in setting
- up the frame (it's OK to skip more, just so long as we don't skip
- anything which might clobber the registers which are being saved.
- Currently we must not skip more on the alpha, but we might the lenient
- stuff some day. */
+ returns an address that (if we're lucky) follows the prologue.
+
+ hppa_skip_prologue is called by gdb to place a breakpoint in a function.
+ It doesn't necessarily skips all the insns in the prologue. In fact
+ we might not want to skip all the insns because a prologue insn may
+ appear in the delay slot of the first branch, and we don't want to
+ skip over the branch in that case. */
static CORE_ADDR
hppa_skip_prologue (CORE_ADDR pc)
if (post_prologue_pc != 0)
return max (pc, post_prologue_pc);
else
- return (skip_prologue_hard_way (pc));
+ return (skip_prologue_hard_way (pc, 1));
+}
+
+/* Return an unwind entry that falls within the frame's code block. */
+static struct unwind_table_entry *
+hppa_find_unwind_entry_in_block (struct frame_info *f)
+{
+ CORE_ADDR pc = frame_unwind_address_in_block (f, NORMAL_FRAME);
+
+ /* FIXME drow/20070101: Calling gdbarch_addr_bits_remove on the
+ result of frame_unwind_address_in_block implies a problem.
+ The bits should have been removed earlier, before the return
+ value of frame_pc_unwind. That might be happening already;
+ if it isn't, it should be fixed. Then this call can be
+ removed. */
+ pc = gdbarch_addr_bits_remove (get_frame_arch (f), pc);
+ return find_unwind_entry (pc);
}
struct hppa_frame_cache
long frame_size;
struct unwind_table_entry *u;
CORE_ADDR prologue_end;
+ int fp_in_r1 = 0;
int i;
if (hppa_debug)
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
/* Yow! */
- u = find_unwind_entry (frame_func_unwind (next_frame));
+ u = hppa_find_unwind_entry_in_block (next_frame);
if (!u)
{
if (hppa_debug)
GCC code. */
{
int final_iteration = 0;
- CORE_ADDR pc, end_pc;
+ CORE_ADDR pc, start_pc, end_pc;
int looking_for_sp = u->Save_SP;
int looking_for_rp = u->Save_RP;
int fp_loc = -1;
- /* We have to use hppa_skip_prologue instead of just
+ /* We have to use skip_prologue_hard_way instead of just
skip_prologue_using_sal, in case we stepped into a function without
symbol information. hppa_skip_prologue also bounds the returned
pc by the passed in pc, so it will not return a pc in the next
- function. */
- prologue_end = hppa_skip_prologue (frame_func_unwind (next_frame));
+ function.
+
+ We used to call hppa_skip_prologue to find the end of the prologue,
+ but if some non-prologue instructions get scheduled into the prologue,
+ and the program is compiled with debug information, the "easy" way
+ in hppa_skip_prologue will return a prologue end that is too early
+ for us to notice any potential frame adjustments. */
+
+ /* We used to use frame_func_unwind () to locate the beginning of the
+ function to pass to skip_prologue (). However, when objects are
+ compiled without debug symbols, frame_func_unwind can return the wrong
+ function (or 0). We can do better than that by using unwind records.
+ This only works if the Region_description of the unwind record
+ indicates that it includes the entry point of the function.
+ HP compilers sometimes generate unwind records for regions that
+ do not include the entry or exit point of a function. GNU tools
+ do not do this. */
+
+ if ((u->Region_description & 0x2) == 0)
+ start_pc = u->region_start;
+ else
+ start_pc = frame_func_unwind (next_frame, NORMAL_FRAME);
+
+ prologue_end = skip_prologue_hard_way (start_pc, 0);
end_pc = frame_pc_unwind (next_frame);
if (prologue_end != 0 && end_pc > prologue_end)
frame_size = 0;
- for (pc = frame_func_unwind (next_frame);
+ for (pc = start_pc;
((saved_gr_mask || saved_fr_mask
|| looking_for_sp || looking_for_rp
|| frame_size < (u->Total_frame_size << 3))
{
int reg;
char buf4[4];
- long status = read_memory_nobpt (pc, buf4, sizeof buf4);
- long inst = extract_unsigned_integer (buf4, sizeof buf4);
+ long inst;
+
+ if (!safe_frame_unwind_memory (next_frame, pc, buf4,
+ sizeof buf4))
+ {
+ error (_("Cannot read instruction at 0x%s."), paddr_nz (pc));
+ return (*this_cache);
+ }
+
+ inst = extract_unsigned_integer (buf4, sizeof buf4);
/* Note the interesting effects of this instruction. */
frame_size += prologue_inst_adjust_sp (inst);
looking_for_rp = 0;
cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
}
- else if (inst == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
+ else if (inst == 0x6bc23fd1) /* stw rp,-0x18(sr0,sp) */
+ {
+ looking_for_rp = 0;
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -24;
+ }
+ else if (inst == 0x0fc212c1
+ || inst == 0x73c23fe1) /* std rp,-0x10(sr0,sp) */
{
looking_for_rp = 0;
cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
looking_for_sp = 0;
cache->saved_regs[HPPA_FP_REGNUM].addr = 0;
}
+ else if (inst == 0x08030241) /* copy %r3, %r1 */
+ {
+ fp_in_r1 = 1;
+ }
/* Account for general and floating-point register saves. */
reg = inst_saves_gr (inst);
the current function (and is thus equivalent to the "saved"
stack pointer. */
CORE_ADDR this_sp = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+ CORE_ADDR fp;
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, " (this_sp=0x%s, pc=0x%s, "
paddr_nz (frame_pc_unwind (next_frame)),
paddr_nz (prologue_end));
- if (frame_pc_unwind (next_frame) >= prologue_end)
+ /* Check to see if a frame pointer is available, and use it for
+ frame unwinding if it is.
+
+ There are some situations where we need to rely on the frame
+ pointer to do stack unwinding. For example, if a function calls
+ alloca (), the stack pointer can get adjusted inside the body of
+ the function. In this case, the ABI requires that the compiler
+ maintain a frame pointer for the function.
+
+ The unwind record has a flag (alloca_frame) that indicates that
+ a function has a variable frame; unfortunately, gcc/binutils
+ does not set this flag. Instead, whenever a frame pointer is used
+ and saved on the stack, the Save_SP flag is set. We use this to
+ decide whether to use the frame pointer for unwinding.
+
+ TODO: For the HP compiler, maybe we should use the alloca_frame flag
+ instead of Save_SP. */
+
+ fp = frame_unwind_register_unsigned (next_frame, HPPA_FP_REGNUM);
+
+ if (u->alloca_frame)
+ fp -= u->Total_frame_size << 3;
+
+ if (frame_pc_unwind (next_frame) >= prologue_end
+ && (u->Save_SP || u->alloca_frame) && fp != 0)
+ {
+ cache->base = fp;
+
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [frame pointer]",
+ paddr_nz (cache->base));
+ }
+ else if (u->Save_SP
+ && trad_frame_addr_p (cache->saved_regs, HPPA_SP_REGNUM))
{
- if (u->Save_SP && trad_frame_addr_p (cache->saved_regs, HPPA_SP_REGNUM))
- {
/* Both we're expecting the SP to be saved and the SP has been
saved. The entry SP value is saved at this frame's SP
address. */
- cache->base = read_memory_integer (this_sp, TARGET_PTR_BIT / 8);
+ cache->base = read_memory_integer
+ (this_sp, gdbarch_ptr_bit (current_gdbarch) / 8);
if (hppa_debug)
- fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [saved] }",
+ fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [saved]",
paddr_nz (cache->base));
- }
- else
- {
- /* The prologue has been slowly allocating stack space. Adjust
- the SP back. */
- cache->base = this_sp - frame_size;
- if (hppa_debug)
- fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [unwind adjust] } ",
- paddr_nz (cache->base));
-
- }
}
else
{
- /* This frame has not yet been created. */
- cache->base = this_sp;
-
+ /* The prologue has been slowly allocating stack space. Adjust
+ the SP back. */
+ cache->base = this_sp - frame_size;
if (hppa_debug)
- fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [before prologue] } ",
+ fprintf_unfiltered (gdb_stdlog, " (base=0x%s) [unwind adjust]",
paddr_nz (cache->base));
}
-
trad_frame_set_value (cache->saved_regs, HPPA_SP_REGNUM, cache->base);
}
as the return register while normal code uses "rp". */
if (u->Millicode)
{
- if (trad_frame_addr_p (cache->saved_regs, HPPA_RP_REGNUM))
- cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[31];
+ if (trad_frame_addr_p (cache->saved_regs, 31))
+ {
+ cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[31];
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, " (pc=r31) [stack] } ");
+ }
else
{
ULONGEST r31 = frame_unwind_register_unsigned (next_frame, 31);
trad_frame_set_value (cache->saved_regs, HPPA_PCOQ_HEAD_REGNUM, r31);
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, " (pc=r31) [frame] } ");
}
}
else
{
if (trad_frame_addr_p (cache->saved_regs, HPPA_RP_REGNUM))
- cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[HPPA_RP_REGNUM];
+ {
+ cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] =
+ cache->saved_regs[HPPA_RP_REGNUM];
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, " (pc=rp) [stack] } ");
+ }
else
{
ULONGEST rp = frame_unwind_register_unsigned (next_frame, HPPA_RP_REGNUM);
trad_frame_set_value (cache->saved_regs, HPPA_PCOQ_HEAD_REGNUM, rp);
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, " (pc=rp) [frame] } ");
}
}
+ /* If Save_SP is set, then we expect the frame pointer to be saved in the
+ frame. However, there is a one-insn window where we haven't saved it
+ yet, but we've already clobbered it. Detect this case and fix it up.
+
+ The prologue sequence for frame-pointer functions is:
+ 0: stw %rp, -20(%sp)
+ 4: copy %r3, %r1
+ 8: copy %sp, %r3
+ c: stw,ma %r1, XX(%sp)
+
+ So if we are at offset c, the r3 value that we want is not yet saved
+ on the stack, but it's been overwritten. The prologue analyzer will
+ set fp_in_r1 when it sees the copy insn so we know to get the value
+ from r1 instead. */
+ if (u->Save_SP && !trad_frame_addr_p (cache->saved_regs, HPPA_FP_REGNUM)
+ && fp_in_r1)
+ {
+ ULONGEST r1 = frame_unwind_register_unsigned (next_frame, 1);
+ trad_frame_set_value (cache->saved_regs, HPPA_FP_REGNUM, r1);
+ }
+
{
/* Convert all the offsets into addresses. */
int reg;
- for (reg = 0; reg < NUM_REGS; reg++)
+ for (reg = 0; reg < gdbarch_num_regs (current_gdbarch); reg++)
{
if (trad_frame_addr_p (cache->saved_regs, reg))
cache->saved_regs[reg].addr += cache->base;
}
}
+ {
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+
+ gdbarch = get_frame_arch (next_frame);
+ tdep = gdbarch_tdep (gdbarch);
+
+ if (tdep->unwind_adjust_stub)
+ {
+ tdep->unwind_adjust_stub (next_frame, cache->base, cache->saved_regs);
+ }
+ }
+
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, "base=0x%s }",
paddr_nz (((struct hppa_frame_cache *)*this_cache)->base));
hppa_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
- struct hppa_frame_cache *info = hppa_frame_cache (next_frame, this_cache);
- (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+ struct hppa_frame_cache *info;
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ struct unwind_table_entry *u;
+
+ info = hppa_frame_cache (next_frame, this_cache);
+ u = hppa_find_unwind_entry_in_block (next_frame);
+
+ (*this_id) = frame_id_build (info->base, u->region_start);
}
static void
void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
struct hppa_frame_cache *info = hppa_frame_cache (next_frame, this_cache);
hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
static const struct frame_unwind *
hppa_frame_unwind_sniffer (struct frame_info *next_frame)
{
- CORE_ADDR pc = frame_pc_unwind (next_frame);
-
- if (find_unwind_entry (pc))
+ if (hppa_find_unwind_entry_in_block (next_frame))
return &hppa_frame_unwind;
return NULL;
hppa_fallback_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct hppa_frame_cache *cache;
- CORE_ADDR pc, start_pc, end_pc, cur_pc;
+ unsigned int frame_size = 0;
+ int found_rp = 0;
+ CORE_ADDR start_pc;
+
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "{ hppa_fallback_frame_cache (frame=%d) -> ",
+ frame_relative_level (next_frame));
cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
(*this_cache) = cache;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- pc = frame_func_unwind (next_frame);
- cur_pc = frame_pc_unwind (next_frame);
-
- find_pc_partial_function (pc, NULL, &start_pc, &end_pc);
-
- if (start_pc == 0 || end_pc == 0)
+ start_pc = frame_func_unwind (next_frame, NORMAL_FRAME);
+ if (start_pc)
{
- error ("Cannot find bounds of current function (@0x%s), unwinding will "
- "fail.", paddr_nz (pc));
- return cache;
- }
+ CORE_ADDR cur_pc = frame_pc_unwind (next_frame);
+ CORE_ADDR pc;
- if (end_pc > cur_pc)
- end_pc = cur_pc;
-
- for (pc = start_pc; pc < end_pc; pc += 4)
- {
- unsigned int insn;
+ for (pc = start_pc; pc < cur_pc; pc += 4)
+ {
+ unsigned int insn;
- insn = read_memory_unsigned_integer (pc, 4);
+ insn = read_memory_unsigned_integer (pc, 4);
+ frame_size += prologue_inst_adjust_sp (insn);
- /* There are limited ways to store the return pointer into the
- stack. */
- if (insn == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
- {
- cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
- break;
- }
- else if (insn == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
- {
- cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
- break;
+ /* There are limited ways to store the return pointer into the
+ stack. */
+ if (insn == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
+ {
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
+ found_rp = 1;
+ }
+ else if (insn == 0x0fc212c1
+ || insn == 0x73c23fe1) /* std rp,-0x10(sr0,sp) */
+ {
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
+ found_rp = 1;
+ }
}
}
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, " frame_size=%d, found_rp=%d }\n",
+ frame_size, found_rp);
+
cache->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+ cache->base -= frame_size;
+ trad_frame_set_value (cache->saved_regs, HPPA_SP_REGNUM, cache->base);
if (trad_frame_addr_p (cache->saved_regs, HPPA_RP_REGNUM))
{
cache->saved_regs[HPPA_RP_REGNUM].addr += cache->base;
- cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[HPPA_RP_REGNUM];
+ cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] =
+ cache->saved_regs[HPPA_RP_REGNUM];
}
else
{
- ULONGEST rp = frame_unwind_register_unsigned (next_frame, HPPA_RP_REGNUM);
+ ULONGEST rp;
+ rp = frame_unwind_register_unsigned (next_frame, HPPA_RP_REGNUM);
trad_frame_set_value (cache->saved_regs, HPPA_PCOQ_HEAD_REGNUM, rp);
}
{
struct hppa_frame_cache *info =
hppa_fallback_frame_cache (next_frame, this_cache);
- (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+ (*this_id) = frame_id_build (info->base,
+ frame_func_unwind (next_frame, NORMAL_FRAME));
}
static void
void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
struct hppa_frame_cache *info =
hppa_fallback_frame_cache (next_frame, this_cache);
return &hppa_fallback_frame_unwind;
}
-static CORE_ADDR
-hppa_frame_base_address (struct frame_info *next_frame,
- void **this_cache)
-{
- struct hppa_frame_cache *info = hppa_frame_cache (next_frame,
- this_cache);
- return info->base;
-}
-
-static const struct frame_base hppa_frame_base = {
- &hppa_frame_unwind,
- hppa_frame_base_address,
- hppa_frame_base_address,
- hppa_frame_base_address
-};
-
-static const struct frame_base *
-hppa_frame_base_sniffer (struct frame_info *next_frame)
-{
- return &hppa_frame_base;
-}
-
/* Stub frames, used for all kinds of call stubs. */
struct hppa_stub_unwind_cache
{
{
struct gdbarch *gdbarch = get_frame_arch (next_frame);
struct hppa_stub_unwind_cache *info;
+ struct unwind_table_entry *u;
if (*this_cache)
return *this_cache;
*this_cache = info;
info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].realreg = HPPA_RP_REGNUM;
info->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+ if (gdbarch_osabi (gdbarch) == GDB_OSABI_HPUX_SOM)
+ {
+ /* HPUX uses export stubs in function calls; the export stub clobbers
+ the return value of the caller, and, later restores it from the
+ stack. */
+ u = find_unwind_entry (frame_pc_unwind (next_frame));
+
+ if (u && u->stub_unwind.stub_type == EXPORT)
+ {
+ info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].addr = info->base - 24;
+
+ return info;
+ }
+ }
+
+ /* By default we assume that stubs do not change the rp. */
+ info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].realreg = HPPA_RP_REGNUM;
+
return info;
}
{
struct hppa_stub_unwind_cache *info
= hppa_stub_frame_unwind_cache (next_frame, this_prologue_cache);
- *this_id = frame_id_build (info->base, frame_pc_unwind (next_frame));
+
+ if (info)
+ *this_id = frame_id_build (info->base,
+ frame_func_unwind (next_frame, NORMAL_FRAME));
+ else
+ *this_id = null_frame_id;
}
static void
void **this_prologue_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
struct hppa_stub_unwind_cache *info
= hppa_stub_frame_unwind_cache (next_frame, this_prologue_cache);
- hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+
+ if (info)
+ hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump,
+ valuep);
+ else
+ error (_("Requesting registers from null frame."));
}
static const struct frame_unwind hppa_stub_frame_unwind = {
static const struct frame_unwind *
hppa_stub_unwind_sniffer (struct frame_info *next_frame)
{
- CORE_ADDR pc = frame_pc_unwind (next_frame);
+ CORE_ADDR pc = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- if (IN_SOLIB_CALL_TRAMPOLINE (pc, NULL)
- || IN_SOLIB_RETURN_TRAMPOLINE (pc, NULL))
+ if (pc == 0
+ || (tdep->in_solib_call_trampoline != NULL
+ && tdep->in_solib_call_trampoline (pc, NULL))
+ || gdbarch_in_solib_return_trampoline (current_gdbarch, pc, NULL))
return &hppa_stub_frame_unwind;
return NULL;
}
frame_pc_unwind (next_frame));
}
-static CORE_ADDR
+CORE_ADDR
hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- return frame_unwind_register_signed (next_frame, HPPA_PCOQ_HEAD_REGNUM) & ~3;
+ ULONGEST ipsw;
+ CORE_ADDR pc;
+
+ ipsw = frame_unwind_register_unsigned (next_frame, HPPA_IPSW_REGNUM);
+ pc = frame_unwind_register_unsigned (next_frame, HPPA_PCOQ_HEAD_REGNUM);
+
+ /* If the current instruction is nullified, then we are effectively
+ still executing the previous instruction. Pretend we are still
+ there. This is needed when single stepping; if the nullified
+ instruction is on a different line, we don't want GDB to think
+ we've stepped onto that line. */
+ if (ipsw & 0x00200000)
+ pc -= 4;
+
+ return pc & ~0x3;
}
-/* Instead of this nasty cast, add a method pvoid() that prints out a
- host VOID data type (remember %p isn't portable). */
+/* Return the minimal symbol whose name is NAME and stub type is STUB_TYPE.
+ Return NULL if no such symbol was found. */
-static CORE_ADDR
-hppa_pointer_to_address_hack (void *ptr)
+struct minimal_symbol *
+hppa_lookup_stub_minimal_symbol (const char *name,
+ enum unwind_stub_types stub_type)
{
- gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
- return POINTER_TO_ADDRESS (builtin_type_void_data_ptr, &ptr);
+ struct objfile *objfile;
+ struct minimal_symbol *msym;
+
+ ALL_MSYMBOLS (objfile, msym)
+ {
+ if (strcmp (SYMBOL_LINKAGE_NAME (msym), name) == 0)
+ {
+ struct unwind_table_entry *u;
+
+ u = find_unwind_entry (SYMBOL_VALUE (msym));
+ if (u != NULL && u->stub_unwind.stub_type == stub_type)
+ return msym;
+ }
+ }
+
+ return NULL;
}
static void
return;
}
- printf_unfiltered ("unwind_table_entry (0x%s):\n",
- paddr_nz (hppa_pointer_to_address_hack (u)));
+ printf_unfiltered ("unwind_table_entry (0x%lx):\n", (unsigned long)u);
printf_unfiltered ("\tregion_start = ");
print_address (u->region_start, gdb_stdout);
+ gdb_flush (gdb_stdout);
printf_unfiltered ("\n\tregion_end = ");
print_address (u->region_end, gdb_stdout);
+ gdb_flush (gdb_stdout);
#define pif(FLD) if (u->FLD) printf_unfiltered (" "#FLD);
pif (Frame_Extension_Millicode);
pif (Stack_Overflow_Check);
pif (Two_Instruction_SP_Increment);
- pif (Ada_Region);
+ pif (sr4export);
+ pif (cxx_info);
+ pif (cxx_try_catch);
+ pif (sched_entry_seq);
pif (Save_SP);
pif (Save_RP);
pif (Save_MRP_in_frame);
- pif (extn_ptr_defined);
+ pif (save_r19);
pif (Cleanup_defined);
pif (MPE_XL_interrupt_marker);
pif (HP_UX_interrupt_marker);
pif (Large_frame);
+ pif (alloca_frame);
putchar_unfiltered ('\n');
pin (Entry_FR);
pin (Entry_GR);
pin (Total_frame_size);
-}
-
-void
-hppa_skip_permanent_breakpoint (void)
-{
- /* To step over a breakpoint instruction on the PA takes some
- fiddling with the instruction address queue.
-
- When we stop at a breakpoint, the IA queue front (the instruction
- we're executing now) points at the breakpoint instruction, and
- the IA queue back (the next instruction to execute) points to
- whatever instruction we would execute after the breakpoint, if it
- were an ordinary instruction. This is the case even if the
- breakpoint is in the delay slot of a branch instruction.
- Clearly, to step past the breakpoint, we need to set the queue
- front to the back. But what do we put in the back? What
- instruction comes after that one? Because of the branch delay
- slot, the next insn is always at the back + 4. */
- write_register (HPPA_PCOQ_HEAD_REGNUM, read_register (HPPA_PCOQ_TAIL_REGNUM));
- write_register (HPPA_PCSQ_HEAD_REGNUM, read_register (HPPA_PCSQ_TAIL_REGNUM));
-
- write_register (HPPA_PCOQ_TAIL_REGNUM, read_register (HPPA_PCOQ_TAIL_REGNUM) + 4);
- /* We can leave the tail's space the same, since there's no jump. */
+ if (u->stub_unwind.stub_type)
+ {
+ printf_unfiltered ("\tstub type = ");
+ switch (u->stub_unwind.stub_type)
+ {
+ case LONG_BRANCH:
+ printf_unfiltered ("long branch\n");
+ break;
+ case PARAMETER_RELOCATION:
+ printf_unfiltered ("parameter relocation\n");
+ break;
+ case EXPORT:
+ printf_unfiltered ("export\n");
+ break;
+ case IMPORT:
+ printf_unfiltered ("import\n");
+ break;
+ case IMPORT_SHLIB:
+ printf_unfiltered ("import shlib\n");
+ break;
+ default:
+ printf_unfiltered ("unknown (%d)\n", u->stub_unwind.stub_type);
+ }
+ }
}
int
minimal symbols, I'm resorting to the gross hack of checking the
top byte of the address for all 1's. Sigh. */
- return (!target_has_stack && (pc & 0xFF000000));
-}
-
-int
-hppa_instruction_nullified (void)
-{
- /* brobecker 2002/11/07: Couldn't we use a ULONGEST here? It would
- avoid the type cast. I'm leaving it as is for now as I'm doing
- semi-mechanical multiarching-related changes. */
- const int ipsw = (int) read_register (HPPA_IPSW_REGNUM);
- const int flags = (int) read_register (HPPA_FLAGS_REGNUM);
-
- return ((ipsw & 0x00200000) && !(flags & 0x2));
+ return (!target_has_stack && (pc & 0xFF000000) == 0xFF000000);
}
-/* Return the GDB type object for the "standard" data type of data
- in register N. */
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. */
static struct type *
-hppa32_register_type (struct gdbarch *gdbarch, int reg_nr)
+hppa32_register_type (struct gdbarch *gdbarch, int regnum)
{
- if (reg_nr < HPPA_FP4_REGNUM)
+ if (regnum < HPPA_FP4_REGNUM)
return builtin_type_uint32;
else
- return builtin_type_ieee_single_big;
+ return builtin_type_ieee_single;
}
-/* Return the GDB type object for the "standard" data type of data
- in register N. hppa64 version. */
-
static struct type *
-hppa64_register_type (struct gdbarch *gdbarch, int reg_nr)
+hppa64_register_type (struct gdbarch *gdbarch, int regnum)
{
- if (reg_nr < HPPA_FP4_REGNUM)
+ if (regnum < HPPA64_FP4_REGNUM)
return builtin_type_uint64;
else
- return builtin_type_ieee_double_big;
+ return builtin_type_ieee_double;
}
-/* Return True if REGNUM is not a register available to the user
- through ptrace(). */
+/* Return non-zero if REGNUM is not a register available to the user
+ through ptrace/ttrace. */
static int
-hppa_cannot_store_register (int regnum)
+hppa32_cannot_store_register (int regnum)
{
return (regnum == 0
|| regnum == HPPA_PCSQ_HEAD_REGNUM
|| (regnum >= HPPA_PCSQ_TAIL_REGNUM && regnum < HPPA_IPSW_REGNUM)
|| (regnum > HPPA_IPSW_REGNUM && regnum < HPPA_FP4_REGNUM));
+}
+static int
+hppa64_cannot_store_register (int regnum)
+{
+ return (regnum == 0
+ || regnum == HPPA_PCSQ_HEAD_REGNUM
+ || (regnum >= HPPA_PCSQ_TAIL_REGNUM && regnum < HPPA_IPSW_REGNUM)
+ || (regnum > HPPA_IPSW_REGNUM && regnum < HPPA64_FP4_REGNUM));
}
static CORE_ADDR
return (addr &= ~0x3);
}
-/* Get the ith function argument for the current function. */
-CORE_ADDR
+/* Get the ARGIth function argument for the current function. */
+
+static CORE_ADDR
hppa_fetch_pointer_argument (struct frame_info *frame, int argi,
struct type *type)
{
- CORE_ADDR addr;
- get_frame_register (frame, HPPA_R0_REGNUM + 26 - argi, &addr);
- return addr;
+ return get_frame_register_unsigned (frame, HPPA_R0_REGNUM + 26 - argi);
}
static void
hppa_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
- int regnum, void *buf)
+ int regnum, gdb_byte *buf)
{
ULONGEST tmp;
regcache_raw_read_unsigned (regcache, regnum, &tmp);
if (regnum == HPPA_PCOQ_HEAD_REGNUM || regnum == HPPA_PCOQ_TAIL_REGNUM)
tmp &= ~0x3;
- store_unsigned_integer (buf, sizeof(tmp), tmp);
+ store_unsigned_integer (buf, sizeof tmp, tmp);
+}
+
+static CORE_ADDR
+hppa_find_global_pointer (struct value *function)
+{
+ return 0;
}
void
struct trad_frame_saved_reg saved_regs[],
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
- int pcoqt = (regnum == HPPA_PCOQ_TAIL_REGNUM);
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
- int regsize = register_size (gdbarch, HPPA_PCOQ_HEAD_REGNUM);
+ struct gdbarch *arch = get_frame_arch (next_frame);
+
+ if (regnum == HPPA_PCOQ_TAIL_REGNUM)
+ {
+ if (valuep)
+ {
+ int size = register_size (arch, HPPA_PCOQ_HEAD_REGNUM);
+ CORE_ADDR pc;
+
+ trad_frame_get_prev_register (next_frame, saved_regs,
+ HPPA_PCOQ_HEAD_REGNUM, optimizedp,
+ lvalp, addrp, realnump, valuep);
+
+ pc = extract_unsigned_integer (valuep, size);
+ store_unsigned_integer (valuep, size, pc + 4);
+ }
+
+ /* It's a computed value. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ return;
+ }
+
+ /* Make sure the "flags" register is zero in all unwound frames.
+ The "flags" registers is a HP-UX specific wart, and only the code
+ in hppa-hpux-tdep.c depends on it. However, it is easier to deal
+ with it here. This shouldn't affect other systems since those
+ should provide zero for the "flags" register anyway. */
+ if (regnum == HPPA_FLAGS_REGNUM)
+ {
+ if (valuep)
+ store_unsigned_integer (valuep, register_size (arch, regnum), 0);
+
+ /* It's a computed value. */
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ return;
+ }
+
+ trad_frame_get_prev_register (next_frame, saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+\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];
- if (pcoqt)
- regnum = HPPA_PCOQ_HEAD_REGNUM;
+ 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 (struct frame_info *frame, 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 = get_frame_register_unsigned (frame, 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 += get_frame_register_unsigned (frame, HPPA_DP_REGNUM);
+ else
+ pc += get_frame_register_unsigned (frame, HPPA_R0_REGNUM + 19);
- trad_frame_prev_register (next_frame, saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ /* 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);
+ }
+ }
- if (pcoqt)
- store_unsigned_integer (valuep, regsize,
- extract_unsigned_integer (valuep, regsize) + 4);
+ 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
else
tdep->bytes_per_address = 4;
+ tdep->find_global_pointer = hppa_find_global_pointer;
+
/* Some parts of the gdbarch vector depend on whether we are running
on a 32 bits or 64 bits target. */
switch (tdep->bytes_per_address)
set_gdbarch_num_regs (gdbarch, hppa32_num_regs);
set_gdbarch_register_name (gdbarch, hppa32_register_name);
set_gdbarch_register_type (gdbarch, hppa32_register_type);
+ set_gdbarch_cannot_store_register (gdbarch,
+ hppa32_cannot_store_register);
+ set_gdbarch_cannot_fetch_register (gdbarch,
+ hppa32_cannot_store_register);
break;
case 8:
set_gdbarch_num_regs (gdbarch, hppa64_num_regs);
set_gdbarch_register_name (gdbarch, hppa64_register_name);
set_gdbarch_register_type (gdbarch, hppa64_register_type);
+ set_gdbarch_dwarf_reg_to_regnum (gdbarch, hppa64_dwarf_reg_to_regnum);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, hppa64_dwarf_reg_to_regnum);
+ set_gdbarch_cannot_store_register (gdbarch,
+ hppa64_cannot_store_register);
+ set_gdbarch_cannot_fetch_register (gdbarch,
+ hppa64_cannot_store_register);
break;
default:
- internal_error (__FILE__, __LINE__, "Unsupported address size: %d",
+ internal_error (__FILE__, __LINE__, _("Unsupported address size: %d"),
tdep->bytes_per_address);
}
and LP64, but might show differences some day. */
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_long_double_bit (gdbarch, 128);
- set_gdbarch_long_double_format (gdbarch, &floatformat_ia64_quad_big);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
/* The following gdbarch vector elements do not depend on the address
size, or in any other gdbarch element previously set. */
set_gdbarch_skip_prologue (gdbarch, hppa_skip_prologue);
+ set_gdbarch_in_function_epilogue_p (gdbarch,
+ hppa_in_function_epilogue_p);
set_gdbarch_inner_than (gdbarch, core_addr_greaterthan);
set_gdbarch_sp_regnum (gdbarch, HPPA_SP_REGNUM);
set_gdbarch_fp0_regnum (gdbarch, HPPA_FP0_REGNUM);
- set_gdbarch_cannot_store_register (gdbarch, hppa_cannot_store_register);
- set_gdbarch_cannot_fetch_register (gdbarch, hppa_cannot_store_register);
set_gdbarch_addr_bits_remove (gdbarch, hppa_smash_text_address);
set_gdbarch_smash_text_address (gdbarch, hppa_smash_text_address);
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
- set_gdbarch_read_pc (gdbarch, hppa_target_read_pc);
- set_gdbarch_write_pc (gdbarch, hppa_target_write_pc);
+ set_gdbarch_read_pc (gdbarch, hppa_read_pc);
+ set_gdbarch_write_pc (gdbarch, hppa_write_pc);
/* Helper for function argument information. */
set_gdbarch_fetch_pointer_argument (gdbarch, hppa_fetch_pointer_argument);
case 4:
set_gdbarch_push_dummy_call (gdbarch, hppa32_push_dummy_call);
set_gdbarch_frame_align (gdbarch, hppa32_frame_align);
+ set_gdbarch_convert_from_func_ptr_addr
+ (gdbarch, hppa32_convert_from_func_ptr_addr);
break;
case 8:
set_gdbarch_push_dummy_call (gdbarch, hppa64_push_dummy_call);
set_gdbarch_frame_align (gdbarch, hppa64_frame_align);
break;
default:
- internal_error (__FILE__, __LINE__, "bad switch");
+ internal_error (__FILE__, __LINE__, _("bad switch"));
}
/* Struct return methods. */
set_gdbarch_return_value (gdbarch, hppa64_return_value);
break;
default:
- internal_error (__FILE__, __LINE__, "bad switch");
+ internal_error (__FILE__, __LINE__, _("bad switch"));
}
set_gdbarch_breakpoint_from_pc (gdbarch, hppa_breakpoint_from_pc);
frame_unwind_append_sniffer (gdbarch, hppa_stub_unwind_sniffer);
frame_unwind_append_sniffer (gdbarch, hppa_frame_unwind_sniffer);
frame_unwind_append_sniffer (gdbarch, hppa_fallback_unwind_sniffer);
- frame_base_append_sniffer (gdbarch, hppa_frame_base_sniffer);
return gdbarch;
}
_initialize_hppa_tdep (void)
{
struct cmd_list_element *c;
- void break_at_finish_command (char *arg, int from_tty);
- void tbreak_at_finish_command (char *arg, int from_tty);
- void break_at_finish_at_depth_command (char *arg, int from_tty);
gdbarch_register (bfd_arch_hppa, hppa_gdbarch_init, hppa_dump_tdep);
hppa_objfile_priv_data = register_objfile_data ();
add_cmd ("unwind", class_maintenance, unwind_command,
- "Print unwind table entry at given address.",
+ _("Print unwind table entry at given address."),
&maintenanceprintlist);
- deprecate_cmd (add_com ("xbreak", class_breakpoint,
- break_at_finish_command,
- concat ("Set breakpoint at procedure exit. \n\
-Argument may be function name, or \"*\" and an address.\n\
-If function is specified, break at end of code for that function.\n\
-If an address is specified, break at the end of the function that contains \n\
-that exact address.\n",
- "With no arg, uses current execution address of selected stack frame.\n\
-This is useful for breaking on return to a stack frame.\n\
-\n\
-Multiple breakpoints at one place are permitted, and useful if conditional.\n\
-\n\
-Do \"help breakpoints\" for info on other commands dealing with breakpoints.", NULL)), NULL);
- deprecate_cmd (add_com_alias ("xb", "xbreak", class_breakpoint, 1), NULL);
- deprecate_cmd (add_com_alias ("xbr", "xbreak", class_breakpoint, 1), NULL);
- deprecate_cmd (add_com_alias ("xbre", "xbreak", class_breakpoint, 1), NULL);
- deprecate_cmd (add_com_alias ("xbrea", "xbreak", class_breakpoint, 1), NULL);
-
- deprecate_cmd (c = add_com ("txbreak", class_breakpoint,
- tbreak_at_finish_command,
-"Set temporary breakpoint at procedure exit. Either there should\n\
-be no argument or the argument must be a depth.\n"), NULL);
- set_cmd_completer (c, location_completer);
-
- if (xdb_commands)
- deprecate_cmd (add_com ("bx", class_breakpoint,
- break_at_finish_at_depth_command,
-"Set breakpoint at procedure exit. Either there should\n\
-be no argument or the argument must be a depth.\n"), NULL);
-
/* Debug this files internals. */
- add_show_from_set (add_set_cmd ("hppa", class_maintenance, var_zinteger,
- &hppa_debug, "Set hppa debugging.\n\
-When non-zero, hppa specific debugging is enabled.", &setdebuglist), &showdebuglist);
+ add_setshow_boolean_cmd ("hppa", class_maintenance, &hppa_debug, _("\
+Set whether hppa target specific debugging information should be displayed."),
+ _("\
+Show whether hppa target specific debugging information is displayed."), _("\
+This flag controls whether hppa target specific debugging information is\n\
+displayed. This information is particularly useful for debugging frame\n\
+unwinding problems."),
+ NULL,
+ NULL, /* FIXME: i18n: hppa debug flag is %s. */
+ &setdebuglist, &showdebuglist);
}
-