summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/binutils/gdb/hppa-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/binutils/gdb/hppa-tdep.c')
-rw-r--r--gnu/usr.bin/binutils/gdb/hppa-tdep.c2732
1 files changed, 2427 insertions, 305 deletions
diff --git a/gnu/usr.bin/binutils/gdb/hppa-tdep.c b/gnu/usr.bin/binutils/gdb/hppa-tdep.c
index b8638ff1c0e..a1da98d37e3 100644
--- a/gnu/usr.bin/binutils/gdb/hppa-tdep.c
+++ b/gnu/usr.bin/binutils/gdb/hppa-tdep.c
@@ -1,6 +1,11 @@
-/* Target-dependent code for PA-RISC.
+/* Target-dependent code for the HP PA architecture, for GDB.
- Copyright 2003, 2004 Free Software Foundation, Inc.
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
+ Foundation, Inc.
+
+ Contributed by the Center for Software Science at the
+ University of Utah (pa-gdb-bugs@cs.utah.edu).
This file is part of GDB.
@@ -20,491 +25,2608 @@
Boston, MA 02111-1307, USA. */
#include "defs.h"
+#include "bfd.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "completer.h"
+#include "osabi.h"
+#include "gdb_assert.h"
#include "arch-utils.h"
-#include "dis-asm.h"
-#include "floatformat.h"
-#include "frame.h"
-#include "frame-base.h"
-#include "frame-unwind.h"
-#include "gdbtypes.h"
+/* For argument passing to the inferior */
#include "symtab.h"
-#include "objfiles.h"
-#include "osabi.h"
-#include "regcache.h"
-#include "target.h"
+#include "dis-asm.h"
#include "trad-frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
-#include "gdb_assert.h"
-
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
#include "hppa-tdep.h"
-/* This file implements a PA-RISC 32-bit ABI. */
-
-/* Please use the hppa32_-prefix for 32-bit specific code, the
- hppa64_-prefix for 64-bit specific code and the sparc_-prefix for
- sparc64-tdep.c. The 64-bit specific code lives in hppa64-tdep.c;
- don't add any here. */
+static int hppa_debug = 0;
+
+/* Some local constants. */
+static const int hppa32_num_regs = 128;
+static const int hppa64_num_regs = 96;
+
+/* hppa-specific object data -- unwind and solib info.
+ TODO/maybe: think about splitting this into two parts; the unwind data is
+ common to all hppa targets, but is only used in this file; we can register
+ that separately and make this static. The solib data is probably hpux-
+ specific, so we can create a separate extern objfile_data that is registered
+ by hppa-hpux-tdep.c and shared with pa64solib.c and somsolib.c. */
+const struct objfile_data *hppa_objfile_priv_data = NULL;
+
+/* Get at various relevent fields of an instruction word. */
+#define MASK_5 0x1f
+#define MASK_11 0x7ff
+#define MASK_14 0x3fff
+#define MASK_21 0x1fffff
+
+/* 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;
+}
-/* The PA-RISCC Floating-Point Quad-Precision format is similar to
- big-endian IA-64 Quad-recision format. */
-#define floatformat_hppa_quad floatformat_ia64_quad_big
+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;
+}
-/* Macros to extract fields from PA-RISC instructions. */
-#define X_OP(i) (((i) >> 26) & 0x3f)
-#define X_B(i) (((i) >> 21) & 0x1f)
-#define X_R(i) (((i) >> 16) & 0x1f)
-#define X_T(i) (((i) >> 16) & 0x1f)
-#define X_IM14(i) ((i) & 0x3fff)
-/* Sign extension macros. */
-#define X_DISP14(i) (low_sign_extend (X_IM14 (i), 14))
+/* Routines to extract various sized constants out of hppa
+ instructions. */
-/* Fetch the instruction at PC. Instructions may be fetched
- big-endian or little-endian dependent on the (optional) E-bit in
- the PSW. Traditionally, the PA-RISC architecture is big-endian
- though. */
+/* This assumes that no garbage lies outside of the lower bits of
+ value. */
-unsigned long
-hppa_fetch_instruction (CORE_ADDR pc)
+int
+hppa_sign_extend (unsigned val, unsigned bits)
{
- unsigned char buf[4];
+ return (int) (val >> (bits - 1) ? (-1 << bits) | val : val);
+}
- /* If we can't read the instruction at PC, return zero. */
- if (target_read_memory (pc, buf, sizeof (buf)))
- return 0;
+/* For many immediate values the sign bit is the low bit! */
- return extract_unsigned_integer (buf, 4);
+int
+hppa_low_hppa_sign_extend (unsigned val, unsigned bits)
+{
+ return (int) ((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
}
-static CORE_ADDR
-hppa_addr_bits_remove (CORE_ADDR addr)
+/* Extract the bits at positions between FROM and TO, using HP's numbering
+ (MSB = 0). */
+
+int
+hppa_get_field (unsigned word, int from, int to)
{
- return addr & ~0x3;
+ return ((word) >> (31 - (to)) & ((1 << ((to) - (from) + 1)) - 1));
}
-static LONGEST
-low_sign_extend (ULONGEST val, ULONGEST bits)
+/* extract the immediate field from a ld{bhw}s instruction */
+
+int
+hppa_extract_5_load (unsigned word)
{
- return (LONGEST) ((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
+ return hppa_low_hppa_sign_extend (word >> 16 & MASK_5, 5);
}
-static const char *hppa32_register_names[] =
+/* extract the immediate field from a break instruction */
+
+unsigned
+hppa_extract_5r_store (unsigned word)
{
- "r0", "r1", "rp", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
- "r24", "r25", "r26", "r27", "r28", "r29", "sp", "r31",
- "sar", "pcoqh", "pcoqt"
-};
+ return (word & MASK_5);
+}
-/* Total number of registers. */
-#define HPPA32_NUM_REGS ARRAY_SIZE (hppa32_register_names)
+/* extract the immediate field from a {sr}sm instruction */
-/* Return the name of register REGNUM. */
+unsigned
+hppa_extract_5R_store (unsigned word)
+{
+ return (word >> 16 & MASK_5);
+}
+
+/* extract a 14 bit immediate field */
-static const char *
-hppa32_register_name (int regnum)
+int
+hppa_extract_14 (unsigned word)
{
- if (regnum >= 0 && regnum < HPPA32_NUM_REGS)
- return hppa32_register_names[regnum];
+ return hppa_low_hppa_sign_extend (word & MASK_14, 14);
+}
- return NULL;
+/* extract a 21 bit constant */
+
+int
+hppa_extract_21 (unsigned word)
+{
+ int val;
+
+ word &= MASK_21;
+ word <<= 11;
+ val = hppa_get_field (word, 20, 20);
+ val <<= 11;
+ val |= hppa_get_field (word, 9, 19);
+ val <<= 2;
+ val |= hppa_get_field (word, 5, 6);
+ val <<= 5;
+ val |= hppa_get_field (word, 0, 4);
+ val <<= 2;
+ val |= hppa_get_field (word, 7, 8);
+ return hppa_sign_extend (val, 21) << 11;
}
-/* Return the GDB type object for the "standard" data type of data in
- register REGNUM. */
+/* extract a 17 bit constant from branch instructions, returning the
+ 19 bit signed value. */
-static struct type *
-hppa32_register_type (struct gdbarch *gdbarch, int regnum)
+int
+hppa_extract_17 (unsigned word)
{
- if (regnum == HPPA_SP_REGNUM)
- return builtin_type_void_data_ptr;
+ return hppa_sign_extend (hppa_get_field (word, 19, 28) |
+ hppa_get_field (word, 29, 29) << 10 |
+ hppa_get_field (word, 11, 15) << 11 |
+ (word & 0x1) << 16, 17) << 2;
+}
- if (regnum == HPPA_RP_REGNUM
- || regnum == HPPA_PCOQ_HEAD_REGNUM
- || regnum == HPPA_PCOQ_TAIL_REGNUM)
- return builtin_type_void_func_ptr;
+CORE_ADDR
+hppa_symbol_address(const char *sym)
+{
+ struct minimal_symbol *minsym;
- return builtin_type_int32;
+ minsym = lookup_minimal_symbol (sym, NULL, NULL);
+ if (minsym)
+ return SYMBOL_VALUE_ADDRESS (minsym);
+ else
+ return (CORE_ADDR)-1;
}
-/* Use the program counter to determine the contents and size of a
- breakpoint instruction. Return a pointer to a string of bytes that
- encode a breakpoint instruction, store the length of the string in
- *LEN and optionally adjust *PC to point to the correct memory
- location for inserting the breakpoint. */
-
-static const unsigned char *
-hppa_breakpoint_from_pc (CORE_ADDR *pc, int *len)
+/* Compare the start address for two unwind entries returning 1 if
+ the first address is larger than the second, -1 if the second is
+ larger than the first, and zero if they are equal. */
+
+static int
+compare_unwind_entries (const void *arg1, const void *arg2)
{
- static unsigned char break_insn[] = { 0x00, 0x01, 0x00, 0x04 };
+ const struct unwind_table_entry *a = arg1;
+ const struct unwind_table_entry *b = arg2;
+
+ if (a->region_start > b->region_start)
+ return 1;
+ else if (a->region_start < b->region_start)
+ return -1;
+ else
+ return 0;
+}
+
+static void
+record_text_segment_lowaddr (bfd *abfd, asection *section, void *data)
+{
+ if ((section->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
+ == (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
+ {
+ bfd_vma value = section->vma - section->filepos;
+ CORE_ADDR *low_text_segment_address = (CORE_ADDR *)data;
- *len = sizeof (break_insn);
- return break_insn;
+ if (value < *low_text_segment_address)
+ *low_text_segment_address = value;
+ }
}
-
-CORE_ADDR
-hppa32_analyze_prologue (CORE_ADDR start_pc, CORE_ADDR current_pc,
- struct hppa_frame_cache *cache)
+static void
+internalize_unwinds (struct objfile *objfile, struct unwind_table_entry *table,
+ asection *section, unsigned int entries, unsigned int size,
+ CORE_ADDR text_offset)
{
- unsigned long insn;
- CORE_ADDR pc;
+ /* We will read the unwind entries into temporary memory, then
+ fill in the actual unwind table. */
- /* When compiling without optimization, GCC uses %r3 as a frame
- pointer and emits the following prologue to set up the stack
- frame:
+ if (size > 0)
+ {
+ unsigned long tmp;
+ unsigned i;
+ char *buf = alloca (size);
+ CORE_ADDR low_text_segment_address;
+
+ /* For ELF targets, then unwinds are supposed to
+ be segment relative offsets instead of absolute addresses.
+
+ Note that when loading a shared library (text_offset != 0) the
+ unwinds are already relative to the text_offset that will be
+ passed in. */
+ if (gdbarch_tdep (current_gdbarch)->is_elf && text_offset == 0)
+ {
+ low_text_segment_address = -1;
- stw %rp,-20(%sp)
- copy %r3,%r1
- copy %r30,%r3
- stwm %r1,d(%sp)
+ bfd_map_over_sections (objfile->obfd,
+ record_text_segment_lowaddr,
+ &low_text_segment_address);
- This instruction sequence is followed by instructions that save
- the callee-saved registers. BSD system call stubs use a somewhat
- different calling convention where the return pointer (%rp) is
- saved in the "External/Stub RP" slot instead of the "Current RP"
- slot. In that case the first instruction is "stw %rp,-24(%sp)". */
+ text_offset = low_text_segment_address;
+ }
- /* We'll increase START_PC as we encounter instructions that we
- recognize as part of the prologue. */
+ bfd_get_section_contents (objfile->obfd, section, buf, 0, size);
- /* If CURRENT_PC isn't set, provide a reasonable default that's
- guaranteed to cover the entire prologue. */
- if (current_pc == (CORE_ADDR) -1)
- current_pc = start_pc + 64;
+ /* Now internalize the information being careful to handle host/target
+ endian issues. */
+ for (i = 0; i < entries; i++)
+ {
+ table[i].region_start = bfd_get_32 (objfile->obfd,
+ (bfd_byte *) buf);
+ table[i].region_start += text_offset;
+ buf += 4;
+ table[i].region_end = bfd_get_32 (objfile->obfd, (bfd_byte *) buf);
+ table[i].region_end += text_offset;
+ buf += 4;
+ tmp = bfd_get_32 (objfile->obfd, (bfd_byte *) buf);
+ buf += 4;
+ table[i].Cannot_unwind = (tmp >> 31) & 0x1;
+ 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].Entry_SR = (tmp >> 25) & 0x1;
+ table[i].Entry_FR = (tmp >> 21) & 0xf;
+ table[i].Entry_GR = (tmp >> 16) & 0x1f;
+ table[i].Args_stored = (tmp >> 15) & 0x1;
+ table[i].Variable_Frame = (tmp >> 14) & 0x1;
+ table[i].Separate_Package_Body = (tmp >> 13) & 0x1;
+ 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].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].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].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].Total_frame_size = tmp & 0x7ffffff;
+
+ /* Stub unwinds are handled elsewhere. */
+ table[i].stub_unwind.stub_type = 0;
+ table[i].stub_unwind.padding = 0;
+ }
+ }
+}
- /* Short-circuit if CURRENT_PC point at the start of this function. */
- else if (current_pc <= start_pc)
- return start_pc;
+/* Read in the backtrace information stored in the `$UNWIND_START$' section of
+ the object file. This info is used mainly by find_unwind_entry() to find
+ out the stack frame size and frame pointer used by procedures. We put
+ everything on the psymbol obstack in the objfile so that it automatically
+ gets freed when the objfile is destroyed. */
- /* Provide a dummy cache if necessary. */
- if (cache == NULL)
+static void
+read_unwind_info (struct objfile *objfile)
+{
+ asection *unwind_sec, *stub_unwind_sec;
+ unsigned unwind_size, stub_unwind_size, total_size;
+ unsigned index, unwind_entries;
+ unsigned stub_entries, total_entries;
+ CORE_ADDR text_offset;
+ struct hppa_unwind_info *ui;
+ struct hppa_objfile_private *obj_private;
+
+ text_offset = ANOFFSET (objfile->section_offsets, 0);
+ ui = (struct hppa_unwind_info *) obstack_alloc (&objfile->objfile_obstack,
+ sizeof (struct hppa_unwind_info));
+
+ ui->table = NULL;
+ ui->cache = NULL;
+ ui->last = -1;
+
+ /* For reasons unknown the HP PA64 tools generate multiple unwinder
+ sections in a single executable. So we just iterate over every
+ section in the BFD looking for unwinder sections intead of trying
+ to do a lookup with bfd_get_section_by_name.
+
+ First determine the total size of the unwind tables so that we
+ can allocate memory in a nice big hunk. */
+ total_entries = 0;
+ for (unwind_sec = objfile->obfd->sections;
+ unwind_sec;
+ unwind_sec = unwind_sec->next)
{
- size_t sizeof_saved_regs =
- HPPA32_NUM_REGS * sizeof (struct trad_frame_saved_reg);
-
- cache = alloca (sizeof (struct hppa_frame_cache));
- cache->saved_regs = alloca (sizeof_saved_regs);
+ if (strcmp (unwind_sec->name, "$UNWIND_START$") == 0
+ || strcmp (unwind_sec->name, ".PARISC.unwind") == 0)
+ {
+ unwind_size = bfd_section_size (objfile->obfd, unwind_sec);
+ unwind_entries = unwind_size / UNWIND_ENTRY_SIZE;
- /* We only initialize the members we care about. */
- cache->frame_size = 0;
- cache->saved_regs[HPPA_R3_REGNUM].realreg = -1;
+ total_entries += unwind_entries;
+ }
}
- for (pc = start_pc; pc < current_pc; pc += 4)
+ /* Now compute the size of the stub unwinds. Note the ELF tools do not
+ use stub unwinds at the curren time. */
+ stub_unwind_sec = bfd_get_section_by_name (objfile->obfd, "$UNWIND_END$");
+
+ if (stub_unwind_sec)
{
- /* Fetch the next instruction. */
- insn = hppa_fetch_instruction (pc);
+ stub_unwind_size = bfd_section_size (objfile->obfd, stub_unwind_sec);
+ stub_entries = stub_unwind_size / STUB_UNWIND_ENTRY_SIZE;
+ }
+ else
+ {
+ stub_unwind_size = 0;
+ stub_entries = 0;
+ }
- /* stw %rp,-20(%sp) or stw %rp,-24(%sp) */
- if (insn == 0x6bc23fd9 || insn == 0x6bc23fd1)
+ /* Compute total number of unwind entries and their total size. */
+ total_entries += stub_entries;
+ total_size = total_entries * sizeof (struct unwind_table_entry);
+
+ /* Allocate memory for the unwind table. */
+ ui->table = (struct unwind_table_entry *)
+ obstack_alloc (&objfile->objfile_obstack, total_size);
+ ui->last = total_entries - 1;
+
+ /* Now read in each unwind section and internalize the standard unwind
+ entries. */
+ index = 0;
+ for (unwind_sec = objfile->obfd->sections;
+ unwind_sec;
+ unwind_sec = unwind_sec->next)
+ {
+ if (strcmp (unwind_sec->name, "$UNWIND_START$") == 0
+ || strcmp (unwind_sec->name, ".PARISC.unwind") == 0)
{
- /* This instruction saves the return pointer (%rp) into the
- "Current RP" slot (or the "External/Stub RP" slot for BSD
- system call stubs) in the in the frame marker. */
- cache->saved_regs[HPPA_RP_REGNUM].addr = X_DISP14 (insn);
- start_pc = pc + 4;
+ unwind_size = bfd_section_size (objfile->obfd, unwind_sec);
+ unwind_entries = unwind_size / UNWIND_ENTRY_SIZE;
+
+ internalize_unwinds (objfile, &ui->table[index], unwind_sec,
+ unwind_entries, unwind_size, text_offset);
+ index += unwind_entries;
}
+ }
+
+ /* Now read in and internalize the stub unwind entries. */
+ if (stub_unwind_size > 0)
+ {
+ unsigned int i;
+ char *buf = alloca (stub_unwind_size);
+
+ /* Read in the stub unwind entries. */
+ bfd_get_section_contents (objfile->obfd, stub_unwind_sec, buf,
+ 0, stub_unwind_size);
- /* copy %r3,%r1 */
- else if (insn == 0x08030241)
+ /* Now convert them into regular unwind entries. */
+ for (i = 0; i < stub_entries; i++, index++)
{
- /* We've found the instruction that saves the frame pointer
- (%r3) into %r1. */
- cache->saved_regs[HPPA_R3_REGNUM].realreg = HPPA_R1_REGNUM;
- start_pc = pc + 4;
+ /* Clear out the next unwind entry. */
+ memset (&ui->table[index], 0, sizeof (struct unwind_table_entry));
+
+ /* Convert offset & size into region_start and region_end.
+ Stuff away the stub type into "reserved" fields. */
+ ui->table[index].region_start = bfd_get_32 (objfile->obfd,
+ (bfd_byte *) buf);
+ ui->table[index].region_start += text_offset;
+ buf += 4;
+ ui->table[index].stub_unwind.stub_type = bfd_get_8 (objfile->obfd,
+ (bfd_byte *) buf);
+ buf += 2;
+ ui->table[index].region_end
+ = ui->table[index].region_start + 4 *
+ (bfd_get_16 (objfile->obfd, (bfd_byte *) buf) - 1);
+ buf += 2;
}
- /* copy %sp,%r3 */
- else if (insn == 0x081e0243)
+ }
+
+ /* Unwind table needs to be kept sorted. */
+ qsort (ui->table, total_entries, sizeof (struct unwind_table_entry),
+ compare_unwind_entries);
+
+ /* Keep a pointer to the unwind information. */
+ 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->unwind_info = ui;
+}
+
+/* Lookup the unwind (stack backtrace) info for the given PC. We search all
+ of the objfiles seeking the unwind table entry for this PC. Each objfile
+ contains a sorted list of struct unwind_table_entry. Since we do a binary
+ search of the unwind tables, we depend upon them to be sorted. */
+
+struct unwind_table_entry *
+find_unwind_entry (CORE_ADDR pc)
+{
+ int first, middle, last;
+ struct objfile *objfile;
+ struct hppa_objfile_private *priv;
+
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ find_unwind_entry 0x%s -> ",
+ paddr_nz (pc));
+
+ /* A function at address 0? Not in HP-UX! */
+ if (pc == (CORE_ADDR) 0)
+ {
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "NULL }\n");
+ return NULL;
+ }
+
+ ALL_OBJFILES (objfile)
+ {
+ struct hppa_unwind_info *ui;
+ ui = NULL;
+ priv = objfile_data (objfile, hppa_objfile_priv_data);
+ if (priv)
+ ui = ((struct hppa_objfile_private *) priv)->unwind_info;
+
+ if (!ui)
+ {
+ read_unwind_info (objfile);
+ priv = objfile_data (objfile, hppa_objfile_priv_data);
+ if (priv == NULL)
+ error ("Internal error reading unwind information.");
+ ui = ((struct hppa_objfile_private *) priv)->unwind_info;
+ }
+
+ /* First, check the cache */
+
+ if (ui->cache
+ && pc >= ui->cache->region_start
+ && pc <= ui->cache->region_end)
+ {
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "0x%s (cached) }\n",
+ paddr_nz ((CORE_ADDR) ui->cache));
+ return ui->cache;
+ }
+
+ /* Not in the cache, do a binary search */
+
+ first = 0;
+ last = ui->last;
+
+ while (first <= last)
+ {
+ middle = (first + last) / 2;
+ if (pc >= ui->table[middle].region_start
+ && pc <= ui->table[middle].region_end)
+ {
+ ui->cache = &ui->table[middle];
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "0x%s }\n",
+ paddr_nz ((CORE_ADDR) ui->cache));
+ return &ui->table[middle];
+ }
+
+ if (pc < ui->table[middle].region_start)
+ last = middle - 1;
+ else
+ first = middle + 1;
+ }
+ } /* ALL_OBJFILES() */
+
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "NULL (not found) }\n");
+
+ return NULL;
+}
+
+static const unsigned char *
+hppa_breakpoint_from_pc (CORE_ADDR *pc, int *len)
+{
+ static const unsigned char breakpoint[] = {0x00, 0x01, 0x00, 0x04};
+ (*len) = sizeof (breakpoint);
+ return breakpoint;
+}
+
+/* Return the name of a register. */
+
+const char *
+hppa32_register_name (int i)
+{
+ static char *names[] = {
+ "flags", "r1", "rp", "r3",
+ "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11",
+ "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19",
+ "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "dp",
+ "ret0", "ret1", "sp", "r31",
+ "sar", "pcoqh", "pcsqh", "pcoqt",
+ "pcsqt", "eiem", "iir", "isr",
+ "ior", "ipsw", "goto", "sr4",
+ "sr0", "sr1", "sr2", "sr3",
+ "sr5", "sr6", "sr7", "cr0",
+ "cr8", "cr9", "ccr", "cr12",
+ "cr13", "cr24", "cr25", "cr26",
+ "mpsfu_high","mpsfu_low","mpsfu_ovflo","pad",
+ "fpsr", "fpe1", "fpe2", "fpe3",
+ "fpe4", "fpe5", "fpe6", "fpe7",
+ "fr4", "fr4R", "fr5", "fr5R",
+ "fr6", "fr6R", "fr7", "fr7R",
+ "fr8", "fr8R", "fr9", "fr9R",
+ "fr10", "fr10R", "fr11", "fr11R",
+ "fr12", "fr12R", "fr13", "fr13R",
+ "fr14", "fr14R", "fr15", "fr15R",
+ "fr16", "fr16R", "fr17", "fr17R",
+ "fr18", "fr18R", "fr19", "fr19R",
+ "fr20", "fr20R", "fr21", "fr21R",
+ "fr22", "fr22R", "fr23", "fr23R",
+ "fr24", "fr24R", "fr25", "fr25R",
+ "fr26", "fr26R", "fr27", "fr27R",
+ "fr28", "fr28R", "fr29", "fr29R",
+ "fr30", "fr30R", "fr31", "fr31R"
+ };
+ if (i < 0 || i >= (sizeof (names) / sizeof (*names)))
+ return NULL;
+ else
+ return names[i];
+}
+
+const char *
+hppa64_register_name (int i)
+{
+ static char *names[] = {
+ "flags", "r1", "rp", "r3",
+ "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11",
+ "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19",
+ "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "dp",
+ "ret0", "ret1", "sp", "r31",
+ "sar", "pcoqh", "pcsqh", "pcoqt",
+ "pcsqt", "eiem", "iir", "isr",
+ "ior", "ipsw", "goto", "sr4",
+ "sr0", "sr1", "sr2", "sr3",
+ "sr5", "sr6", "sr7", "cr0",
+ "cr8", "cr9", "ccr", "cr12",
+ "cr13", "cr24", "cr25", "cr26",
+ "mpsfu_high","mpsfu_low","mpsfu_ovflo","pad",
+ "fpsr", "fpe1", "fpe2", "fpe3",
+ "fr4", "fr5", "fr6", "fr7",
+ "fr8", "fr9", "fr10", "fr11",
+ "fr12", "fr13", "fr14", "fr15",
+ "fr16", "fr17", "fr18", "fr19",
+ "fr20", "fr21", "fr22", "fr23",
+ "fr24", "fr25", "fr26", "fr27",
+ "fr28", "fr29", "fr30", "fr31"
+ };
+ if (i < 0 || i >= (sizeof (names) / sizeof (*names)))
+ return NULL;
+ else
+ return names[i];
+}
+
+/* This function pushes a stack frame with arguments as part of the
+ inferior function calling mechanism.
+
+ This is the version of the function for the 32-bit PA machines, in
+ which later arguments appear at lower addresses. (The stack always
+ grows towards higher addresses.)
+
+ 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, 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)
+{
+ /* 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;
+
+ /* The inner most end of the stack after all the parameters have
+ been pushed. */
+ CORE_ADDR new_sp = 0;
+
+ /* 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;
+ /* The first parameter goes into sp-36, each stack slot is 4-bytes.
+ struct_ptr is adjusted for each argument below, so the first
+ argument will end up at sp-36. */
+ CORE_ADDR param_ptr = 32;
+ int i;
+ int small_struct = 0;
+
+ for (i = 0; i < nargs; i++)
{
- /* We've found the instruction that sets up the new frame
- pointer. */
- cache->saved_regs[HPPA_SP_REGNUM].realreg = HPPA_R3_REGNUM;
- start_pc = pc + 4;
+ struct value *arg = args[i];
+ 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];
+ int param_len;
+ memset (param_val, 0, sizeof param_val);
+ if (TYPE_LENGTH (type) > 8)
+ {
+ /* Large parameter, pass by reference. Store the value
+ in "struct" area and then pass its address. */
+ param_len = 4;
+ struct_ptr += align_up (TYPE_LENGTH (type), 8);
+ if (write_pass)
+ write_memory (struct_end - struct_ptr, VALUE_CONTENTS (arg),
+ TYPE_LENGTH (type));
+ store_unsigned_integer (param_val, 4, struct_end - struct_ptr);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_ENUM)
+ {
+ /* Integer value store, right aligned. "unpack_long"
+ takes care of any sign-extension problems. */
+ param_len = align_up (TYPE_LENGTH (type), 4);
+ store_unsigned_integer (param_val, param_len,
+ unpack_long (type,
+ 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);
+ }
+ else
+ {
+ param_len = align_up (TYPE_LENGTH (type), 4);
+
+ /* Small struct value are stored right-aligned. */
+ memcpy (param_val + param_len - 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 && param_len < 8)
+ small_struct = 1;
+ }
+
+ param_ptr += param_len;
+ if (param_len == 8 && !small_struct)
+ param_ptr = align_up (param_ptr, 8);
+
+ /* First 4 non-FP arguments are passed in gr26-gr23.
+ First 4 32-bit FP arguments are passed in fr4L-fr7L.
+ First 2 64-bit FP arguments are passed in fr5 and fr7.
+
+ The rest go on the stack, starting at sp-36, towards lower
+ addresses. 8-byte arguments must be aligned to a 8-byte
+ stack boundary. */
+ if (write_pass)
+ {
+ write_memory (param_end - param_ptr, param_val, param_len);
+
+ /* There are some cases when we don't know the type
+ expected by the callee (e.g. for variadic functions), so
+ pass the parameters in both general and fp regs. */
+ if (param_ptr <= 48)
+ {
+ int grreg = 26 - (param_ptr - 36) / 4;
+ int fpLreg = 72 + (param_ptr - 36) / 4 * 2;
+ int fpreg = 74 + (param_ptr - 32) / 8 * 4;
+
+ regcache_cooked_write (regcache, grreg, param_val);
+ regcache_cooked_write (regcache, fpLreg, param_val);
+
+ if (param_len > 4)
+ {
+ regcache_cooked_write (regcache, grreg + 1,
+ param_val + 4);
+
+ regcache_cooked_write (regcache, fpreg, param_val);
+ regcache_cooked_write (regcache, fpreg + 1,
+ param_val + 4);
+ }
+ }
+ }
}
- else if (X_OP (insn) == 0x1b && X_B (insn) == HPPA_SP_REGNUM
- && X_R (insn) == HPPA_R1_REGNUM && X_DISP14 (insn) > 0)
+ /* Update the various stack pointers. */
+ if (!write_pass)
{
- /* We've found the instruction that saves the old frame
- pointer (living in %r1) onto the stack. */
- cache->saved_regs[HPPA_R3_REGNUM].addr = 0;
- start_pc = pc + 4;
+ struct_end = sp + align_up (struct_ptr, 64);
+ /* 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 + align_up (param_ptr, 64);
+ }
+ }
- /* Only set the frame size of we don't have a frame pointer. */
- if (cache->saved_regs[HPPA_SP_REGNUM].realreg != HPPA_R3_REGNUM)
- cache->frame_size = X_DISP14 (insn);
+ /* If a structure has to be returned, set up register 28 to hold its
+ address */
+ if (struct_return)
+ write_register (28, struct_addr);
- /* The frame is fully set up now. */
- return pc + 4;
- }
+ gp = tdep->find_global_pointer (function);
+
+ if (gp != 0)
+ write_register (19, gp);
+
+ /* Set the return address. */
+ 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;
+}
- /* stwm r,d(%sp) */
- else if (X_OP (insn) == 0x1b && X_B (insn) == HPPA_SP_REGNUM
- && X_R (insn) >= HPPA_R3_REGNUM
- && X_R (insn) <= HPPA_R18_REGNUM
- && X_DISP14 (insn) > 0)
+/* This function pushes a stack frame with arguments as part of the
+ inferior function calling mechanism.
+
+ This is the version for the PA64, in which later arguments appear
+ at higher addresses. (The stack always grows towards higher
+ addresses.)
+
+ We simply allocate the appropriate amount of stack space and put
+ arguments into their proper slots.
+
+ 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, 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;
+
+ /* The inner most end of the stack after all the parameters have
+ been pushed. */
+ CORE_ADDR new_sp = 0;
+
+ /* 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++)
+ {
+ CORE_ADDR struct_ptr = 0;
+ CORE_ADDR param_ptr = 0;
+ int i;
+ for (i = 0; i < nargs; i++)
{
- /* stwm %r1,d(%sp) */
- if (X_R (insn) == HPPA_R1_REGNUM
- && cache->saved_regs[HPPA_R3_REGNUM].realreg == HPPA_R1_REGNUM)
- cache->saved_regs[HPPA_R3_REGNUM].addr = 0;
+ 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)
+ {
+ /* 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);
+ }
+ }
else
- cache->saved_regs[X_R (insn)].addr = 0;
+ {
+ /* Small struct value, store left aligned? */
+ int reg;
+ if (TYPE_LENGTH (type) > 8)
+ {
+ param_ptr = align_up (param_ptr, 16);
+ reg = 26 - param_ptr / 8;
+ param_ptr += align_up (TYPE_LENGTH (type), 16);
+ }
+ else
+ {
+ param_ptr = align_up (param_ptr, 8);
+ reg = 26 - param_ptr / 8;
+ param_ptr += align_up (TYPE_LENGTH (type), 8);
+ }
+ if (write_pass)
+ {
+ 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--;
+ }
+ }
+ }
+ }
+ /* Update the various stack pointers. */
+ if (!write_pass)
+ {
+ 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);
+ }
+ }
- /* Only set the frame size of we don't have a frame pointer. */
- if (cache->saved_regs[HPPA_SP_REGNUM].realreg != HPPA_R3_REGNUM)
- cache->frame_size = X_DISP14 (insn);
+ /* If a structure has to be returned, set up register 28 to hold its
+ address */
+ if (struct_return)
+ write_register (28, struct_addr);
+
+ /* Set the return address. */
+ regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
+
+ /* Update the Stack Pointer. */
+ regcache_cooked_write_unsigned (regcache, HPPA_SP_REGNUM, param_end + 64);
+
+ /* The stack will have 32 bytes of additional space for a frame marker. */
+ return param_end + 64;
+}
- /* The frame is fully set up now. */
- return pc + 4;
+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;
+
+ plabel = addr & ~3;
+ target_read_memory(plabel, (char *)&addr, 4);
+ }
+
+ return addr;
+}
+
+static CORE_ADDR
+hppa32_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ /* HP frames are 64-byte (or cache line) aligned (yes that's _byte_
+ and not _bit_)! */
+ return align_up (addr, 64);
+}
+
+/* Force all frames to 16-byte alignment. Better safe than sorry. */
+
+static CORE_ADDR
+hppa64_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ /* Just always 16-byte align. */
+ 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)
+{
+ 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. */
+ /* Test SS_INSYSCALL */
+ if (flags & 2)
+ return read_register_pid (31, ptid) & ~0x3;
+
+ return read_register_pid (HPPA_PCOQ_HEAD_REGNUM, ptid) & ~0x3;
+}
+
+/* Write out the PC. If currently in a syscall, then also write the new
+ PC value into %r31. */
+
+static void
+hppa_target_write_pc (CORE_ADDR v, ptid_t ptid)
+{
+ 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);
+}
+
+/* return the alignment of a type in bytes. Structures have the maximum
+ alignment required by their fields. */
+
+static int
+hppa_alignof (struct type *type)
+{
+ int max_align, align, i;
+ CHECK_TYPEDEF (type);
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ return TYPE_LENGTH (type);
+ case TYPE_CODE_ARRAY:
+ return hppa_alignof (TYPE_FIELD_TYPE (type, 0));
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ max_align = 1;
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ /* Bit fields have no real alignment. */
+ /* if (!TYPE_FIELD_BITPOS (type, i)) */
+ if (!TYPE_FIELD_BITSIZE (type, i)) /* elz: this should be bitsize */
+ {
+ align = hppa_alignof (TYPE_FIELD_TYPE (type, i));
+ max_align = max (max_align, align);
+ }
+ }
+ return max_align;
+ default:
+ return 4;
+ }
+}
+
+/* For the given instruction (INST), return any adjustment it makes
+ to the stack pointer or zero for no adjustment.
+
+ This only handles instructions commonly found in prologues. */
+
+static int
+prologue_inst_adjust_sp (unsigned long inst)
+{
+ /* This must persist across calls. */
+ static int save_high21;
+
+ /* The most common way to perform a stack adjustment ldo X(sp),sp */
+ if ((inst & 0xffffc000) == 0x37de0000)
+ return hppa_extract_14 (inst);
+
+ /* stwm X,D(sp) */
+ if ((inst & 0xffe00000) == 0x6fc00000)
+ return hppa_extract_14 (inst);
+
+ /* std,ma X,D(sp) */
+ if ((inst & 0xffe00008) == 0x73c00008)
+ return (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
+
+ /* addil high21,%r1; ldo low11,(%r1),%r30)
+ save high bits in save_high21 for later use. */
+ if ((inst & 0xffe00000) == 0x28200000)
+ {
+ save_high21 = hppa_extract_21 (inst);
+ return 0;
+ }
+
+ if ((inst & 0xffff0000) == 0x343e0000)
+ return save_high21 + hppa_extract_14 (inst);
+
+ /* fstws as used by the HP compilers. */
+ if ((inst & 0xffffffe0) == 0x2fd01220)
+ return hppa_extract_5_load (inst);
+
+ /* No adjustment. */
+ return 0;
+}
+
+/* Return nonzero if INST is a branch of some kind, else return zero. */
+
+static int
+is_branch (unsigned long inst)
+{
+ switch (inst >> 26)
+ {
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2f:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Return the register number for a GR which is saved by INST or
+ zero it INST does not save a GR. */
+
+static int
+inst_saves_gr (unsigned long inst)
+{
+ /* Does it look like a stw? */
+ if ((inst >> 26) == 0x1a || (inst >> 26) == 0x1b
+ || (inst >> 26) == 0x1f
+ || ((inst >> 26) == 0x1f
+ && ((inst >> 6) == 0xa)))
+ return hppa_extract_5R_store (inst);
+
+ /* Does it look like a std? */
+ if ((inst >> 26) == 0x1c
+ || ((inst >> 26) == 0x03
+ && ((inst >> 6) & 0xf) == 0xb))
+ return hppa_extract_5R_store (inst);
+
+ /* Does it look like a stwm? GCC & HPC may use this in prologues. */
+ if ((inst >> 26) == 0x1b)
+ return hppa_extract_5R_store (inst);
+
+ /* Does it look like sth or stb? HPC versions 9.0 and later use these
+ too. */
+ if ((inst >> 26) == 0x19 || (inst >> 26) == 0x18
+ || ((inst >> 26) == 0x3
+ && (((inst >> 6) & 0xf) == 0x8
+ || (inst >> 6) & 0xf) == 0x9))
+ return hppa_extract_5R_store (inst);
+
+ return 0;
+}
+
+/* Return the register number for a FR which is saved by INST or
+ zero it INST does not save a FR.
+
+ Note we only care about full 64bit register stores (that's the only
+ kind of stores the prologue will use).
+
+ FIXME: What about argument stores with the HP compiler in ANSI mode? */
+
+static int
+inst_saves_fr (unsigned long inst)
+{
+ /* is this an FSTD ? */
+ if ((inst & 0xfc00dfc0) == 0x2c001200)
+ return hppa_extract_5r_store (inst);
+ if ((inst & 0xfc000002) == 0x70000002)
+ return hppa_extract_5R_store (inst);
+ /* is this an FSTW ? */
+ if ((inst & 0xfc00df80) == 0x24001200)
+ return hppa_extract_5r_store (inst);
+ if ((inst & 0xfc000002) == 0x7c000000)
+ return hppa_extract_5R_store (inst);
+ return 0;
+}
+
+/* Advance PC across any function entry prologue instructions
+ to reach some "real" code.
+
+ Use information in the unwind table to determine what exactly should
+ be in the prologue. */
+
+
+CORE_ADDR
+skip_prologue_hard_way (CORE_ADDR pc)
+{
+ 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;
+
+ restart_gr = 0;
+ restart_fr = 0;
+
+restart:
+ u = find_unwind_entry (pc);
+ if (!u)
+ return pc;
+
+ /* If we are not at the beginning of a function, then return now. */
+ if ((pc & ~0x3) != u->region_start)
+ return pc;
+
+ /* This is how much of a frame adjustment we need to account for. */
+ stack_remaining = u->Total_frame_size << 3;
+
+ /* Magic register saves we want to know about. */
+ save_rp = u->Save_RP;
+ save_sp = u->Save_SP;
+
+ /* An indication that args may be stored into the stack. Unfortunately
+ the HPUX compilers tend to set this in cases where no args were
+ stored too!. */
+ args_stored = 1;
+
+ /* Turn the Entry_GR field into a bitmask. */
+ save_gr = 0;
+ for (i = 3; i < u->Entry_GR + 3; i++)
+ {
+ /* Frame pointer gets saved into a special location. */
+ if (u->Save_SP && i == HPPA_FP_REGNUM)
+ continue;
+
+ save_gr |= (1 << i);
+ }
+ save_gr &= ~restart_gr;
+
+ /* Turn the Entry_FR field into a bitmask too. */
+ save_fr = 0;
+ for (i = 12; i < u->Entry_FR + 12; i++)
+ save_fr |= (1 << i);
+ save_fr &= ~restart_fr;
+
+ /* 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
+ examine any user instructions.
+
+ For optimzied GCC code we're faced with problems. GCC will schedule
+ its prologue and make prologue instructions available for delay slot
+ filling. The end result is user code gets mixed in with the prologue
+ and a prologue instruction may be in the delay slot of the first branch
+ or call.
+
+ Some unexpected things are expected with debugging optimized code, so
+ we allow this routine to walk past user instructions in optimized
+ GCC code. */
+ while (save_gr || save_fr || save_rp || save_sp || stack_remaining > 0
+ || args_stored)
+ {
+ unsigned int reg_num;
+ unsigned long old_stack_remaining, old_save_gr, old_save_fr;
+ unsigned long old_save_rp, old_save_sp, next_inst;
+
+ /* Save copies of all the triggers so we can compare them later
+ (only for HPC). */
+ old_save_gr = save_gr;
+ old_save_fr = save_fr;
+ old_save_rp = save_rp;
+ old_save_sp = save_sp;
+ old_stack_remaining = stack_remaining;
+
+ status = deprecated_read_memory_nobpt (pc, buf, 4);
+ inst = extract_unsigned_integer (buf, 4);
+
+ /* Yow! */
+ if (status != 0)
+ return pc;
+
+ /* Note the interesting effects of this instruction. */
+ stack_remaining -= prologue_inst_adjust_sp (inst);
+
+ /* There are limited ways to store the return pointer into the
+ stack. */
+ if (inst == 0x6bc23fd9 || inst == 0x0fc212c1)
+ save_rp = 0;
+
+ /* These are the only ways we save SP into the stack. At this time
+ the HP compilers never bother to save SP into the stack. */
+ if ((inst & 0xffffc000) == 0x6fc10000
+ || (inst & 0xffffc00c) == 0x73c10008)
+ save_sp = 0;
+
+ /* Are we loading some register with an offset from the argument
+ pointer? */
+ if ((inst & 0xffe00000) == 0x37a00000
+ || (inst & 0xffffffe0) == 0x081d0240)
+ {
+ pc += 4;
+ continue;
}
- /* ldo d(%sp),%sp */
- else if (X_OP (insn) == 0x0d && X_B (insn) == HPPA_SP_REGNUM
- && X_T (insn) == HPPA_SP_REGNUM && X_DISP14 (insn) > 0)
+ /* Account for general and floating-point register saves. */
+ reg_num = inst_saves_gr (inst);
+ save_gr &= ~(1 << reg_num);
+
+ /* Ugh. Also account for argument stores into the stack.
+ Unfortunately args_stored only tells us that some arguments
+ where stored into the stack. Not how many or what kind!
+
+ 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. We have similar code for the fp arg stores below.
+
+ 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)
{
- cache->frame_size = X_DISP14 (insn);
+ while (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
+ {
+ pc += 4;
+ status = deprecated_read_memory_nobpt (pc, buf, 4);
+ inst = extract_unsigned_integer (buf, 4);
+ if (status != 0)
+ return pc;
+ reg_num = inst_saves_gr (inst);
+ }
+ args_stored = 0;
+ continue;
+ }
+
+ reg_num = inst_saves_fr (inst);
+ save_fr &= ~(1 << reg_num);
- /* Only set the frame size of we don't have a frame pointer. */
- if (cache->saved_regs[HPPA_SP_REGNUM].realreg != HPPA_R3_REGNUM)
- cache->frame_size = X_DISP14 (insn);
+ status = deprecated_read_memory_nobpt (pc + 4, buf, 4);
+ next_inst = extract_unsigned_integer (buf, 4);
- /* The frame is fully set up now. */
- return pc + 4;
+ /* Yow! */
+ if (status != 0)
+ return pc;
+
+ /* We've got to be read to handle the ldo before the fp register
+ save. */
+ if ((inst & 0xfc000000) == 0x34000000
+ && inst_saves_fr (next_inst) >= 4
+ && inst_saves_fr (next_inst) <= (TARGET_PTR_BIT == 64 ? 11 : 7))
+ {
+ /* So we drop into the code below in a reasonable state. */
+ reg_num = inst_saves_fr (next_inst);
+ pc -= 4;
}
+
+ /* Ugh. Also account for argument stores into the stack.
+ 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))
+ {
+ while (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
+ {
+ pc += 8;
+ status = deprecated_read_memory_nobpt (pc, buf, 4);
+ inst = extract_unsigned_integer (buf, 4);
+ if (status != 0)
+ return pc;
+ if ((inst & 0xfc000000) != 0x34000000)
+ break;
+ status = deprecated_read_memory_nobpt (pc + 4, buf, 4);
+ next_inst = extract_unsigned_integer (buf, 4);
+ if (status != 0)
+ return pc;
+ reg_num = inst_saves_fr (next_inst);
+ }
+ args_stored = 0;
+ continue;
+ }
+
+ /* 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))
+ break;
+
+ /* What a crock. The HP compilers set args_stored even if no
+ arguments were stored into the stack (boo hiss). This could
+ cause this code to then skip a bunch of user insns (up to the
+ first branch).
+
+ To combat this we try to identify when args_stored was bogusly
+ set and clear it. We only do this when args_stored is nonzero,
+ all other resources are accounted for, and nothing changed on
+ this pass. */
+ if (args_stored
+ && !(save_gr || save_fr || save_rp || save_sp || stack_remaining > 0)
+ && old_save_gr == save_gr && old_save_fr == save_fr
+ && old_save_rp == save_rp && old_save_sp == save_sp
+ && old_stack_remaining == stack_remaining)
+ break;
+
+ /* Bump the PC. */
+ pc += 4;
}
- return start_pc;
+ /* We've got a tenative location for the end of the prologue. However
+ because of limitations in the unwind descriptor mechanism we may
+ have went too far into user code looking for the save of a register
+ that does not exist. So, if there registers we expected to be saved
+ but never were, mask them out and restart.
+
+ This should only happen in optimized code, and should be very rare. */
+ if (save_gr || (save_fr && !(restart_fr || restart_gr)))
+ {
+ pc = orig_pc;
+ restart_gr = save_gr;
+ restart_fr = save_fr;
+ goto restart;
+ }
+
+ return pc;
}
+
+/* Return the address of the PC after the last prologue instruction if
+ we can determine it from the debug symbols. Else return zero. */
+
static CORE_ADDR
-hppa32_skip_prologue (CORE_ADDR start_pc)
+after_prologue (CORE_ADDR pc)
{
struct symtab_and_line sal;
- CORE_ADDR func_start, func_end;
+ CORE_ADDR func_addr, func_end;
+ struct symbol *f;
+
+ /* If we can not find the symbol in the partial symbol table, then
+ there is no hope we can determine the function's start address
+ with this code. */
+ if (!find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ return 0;
+
+ /* Get the line associated with FUNC_ADDR. */
+ sal = find_pc_line (func_addr, 0);
+
+ /* There are only two cases to consider. First, the end of the source line
+ is within the function bounds. In that case we return the end of the
+ source line. Second is the end of the source line extends beyond the
+ bounds of the current function. We need to use the slow code to
+ examine instructions in that case.
+
+ Anything else is simply a bug elsewhere. Fixing it here is absolutely
+ the wrong thing to do. In fact, it should be entirely possible for this
+ function to always return zero since the slow instruction scanning code
+ is supposed to *always* work. If it does not, then it is a bug. */
+ if (sal.end < func_end)
+ return sal.end;
+ else
+ return 0;
+}
- /* This is the preferred method, find the end of the prologue by
- using the debugging information. */
- if (find_pc_partial_function (start_pc, NULL, &func_start, &func_end))
+/* 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. */
+
+static CORE_ADDR
+hppa_skip_prologue (CORE_ADDR pc)
+{
+ unsigned long inst;
+ int offset;
+ CORE_ADDR post_prologue_pc;
+ char buf[4];
+
+ /* See if we can determine the end of the prologue via the symbol table.
+ If so, then return either PC, or the PC after the prologue, whichever
+ is greater. */
+
+ post_prologue_pc = after_prologue (pc);
+
+ /* If after_prologue returned a useful address, then use it. Else
+ fall back on the instruction skipping code.
+
+ Some folks have claimed this causes problems because the breakpoint
+ may be the first instruction of the prologue. If that happens, then
+ the instruction skipping code has a bug that needs to be fixed. */
+ if (post_prologue_pc != 0)
+ return max (pc, post_prologue_pc);
+ else
+ return (skip_prologue_hard_way (pc));
+}
+
+struct hppa_frame_cache
+{
+ CORE_ADDR base;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+static struct hppa_frame_cache *
+hppa_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct hppa_frame_cache *cache;
+ long saved_gr_mask;
+ long saved_fr_mask;
+ CORE_ADDR this_sp;
+ long frame_size;
+ struct unwind_table_entry *u;
+ CORE_ADDR prologue_end;
+ int i;
+
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ hppa_frame_cache (frame=%d) -> ",
+ frame_relative_level(next_frame));
+
+ if ((*this_cache) != NULL)
{
- sal = find_pc_line (func_start, 0);
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "base=0x%s (cached) }",
+ paddr_nz (((struct hppa_frame_cache *)*this_cache)->base));
+ return (*this_cache);
+ }
+ cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
+ (*this_cache) = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- if (sal.end < func_end
- && start_pc <= sal.end)
- return sal.end;
+ /* Yow! */
+ u = find_unwind_entry (frame_pc_unwind (next_frame));
+ if (!u)
+ {
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "base=NULL (no unwind entry) }");
+ return (*this_cache);
}
- /* Analyze the prologue. */
- return hppa32_analyze_prologue (start_pc, (CORE_ADDR) -1, NULL);
+ /* Turn the Entry_GR field into a bitmask. */
+ saved_gr_mask = 0;
+ for (i = 3; i < u->Entry_GR + 3; i++)
+ {
+ /* Frame pointer gets saved into a special location. */
+ if (u->Save_SP && i == HPPA_FP_REGNUM)
+ continue;
+
+ saved_gr_mask |= (1 << i);
+ }
+
+ /* Turn the Entry_FR field into a bitmask too. */
+ saved_fr_mask = 0;
+ for (i = 12; i < u->Entry_FR + 12; i++)
+ saved_fr_mask |= (1 << i);
+
+ /* 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
+ examine any user instructions.
+
+ For optimized GCC code we're faced with problems. GCC will schedule
+ its prologue and make prologue instructions available for delay slot
+ filling. The end result is user code gets mixed in with the prologue
+ and a prologue instruction may be in the delay slot of the first branch
+ or call.
+
+ Some unexpected things are expected with debugging optimized code, so
+ we allow this routine to walk past user instructions in optimized
+ GCC code. */
+ {
+ int final_iteration = 0;
+ CORE_ADDR 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
+ 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. */
+
+ /* 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. */
+
+ prologue_end = hppa_skip_prologue (u->region_start);
+ end_pc = frame_pc_unwind (next_frame);
+
+ if (prologue_end != 0 && end_pc > prologue_end)
+ end_pc = prologue_end;
+
+ frame_size = 0;
+
+ for (pc = u->region_start;
+ ((saved_gr_mask || saved_fr_mask
+ || looking_for_sp || looking_for_rp
+ || frame_size < (u->Total_frame_size << 3))
+ && pc < end_pc);
+ pc += 4)
+ {
+ int reg;
+ char buf4[4];
+ long status = deprecated_read_memory_nobpt (pc, buf4, sizeof buf4);
+ long inst = extract_unsigned_integer (buf4, sizeof buf4);
+
+ /* Note the interesting effects of this instruction. */
+ frame_size += prologue_inst_adjust_sp (inst);
+
+ /* There are limited ways to store the return pointer into the
+ stack. */
+ if (inst == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
+ {
+ looking_for_rp = 0;
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -20;
+ }
+ 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) /* std rp,-0x10(sr0,sp) */
+ {
+ looking_for_rp = 0;
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
+ }
+
+ /* Check to see if we saved SP into the stack. This also
+ happens to indicate the location of the saved frame
+ pointer. */
+ if ((inst & 0xffffc000) == 0x6fc10000 /* stw,ma r1,N(sr0,sp) */
+ || (inst & 0xffffc00c) == 0x73c10008) /* std,ma r1,N(sr0,sp) */
+ {
+ looking_for_sp = 0;
+ cache->saved_regs[HPPA_FP_REGNUM].addr = 0;
+ }
+
+ /* Account for general and floating-point register saves. */
+ reg = inst_saves_gr (inst);
+ if (reg >= 3 && reg <= 18
+ && (!u->Save_SP || reg != HPPA_FP_REGNUM))
+ {
+ saved_gr_mask &= ~(1 << reg);
+ if ((inst >> 26) == 0x1b && hppa_extract_14 (inst) >= 0)
+ /* stwm with a positive displacement is a _post_
+ _modify_. */
+ cache->saved_regs[reg].addr = 0;
+ else if ((inst & 0xfc00000c) == 0x70000008)
+ /* A std has explicit post_modify forms. */
+ cache->saved_regs[reg].addr = 0;
+ else
+ {
+ CORE_ADDR offset;
+
+ if ((inst >> 26) == 0x1c)
+ offset = (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
+ else if ((inst >> 26) == 0x03)
+ offset = hppa_low_hppa_sign_extend (inst & 0x1f, 5);
+ else
+ offset = hppa_extract_14 (inst);
+
+ /* Handle code with and without frame pointers. */
+ if (u->Save_SP)
+ cache->saved_regs[reg].addr = offset;
+ else
+ cache->saved_regs[reg].addr = (u->Total_frame_size << 3) + offset;
+ }
+ }
+
+ /* GCC handles callee saved FP regs a little differently.
+
+ It emits an instruction to put the value of the start of
+ the FP store area into %r1. It then uses fstds,ma with a
+ basereg of %r1 for the stores.
+
+ HP CC emits them at the current stack pointer modifying the
+ stack pointer as it stores each register. */
+
+ /* ldo X(%r3),%r1 or ldo X(%r30),%r1. */
+ if ((inst & 0xffffc000) == 0x34610000
+ || (inst & 0xffffc000) == 0x37c10000)
+ fp_loc = hppa_extract_14 (inst);
+
+ reg = inst_saves_fr (inst);
+ if (reg >= 12 && reg <= 21)
+ {
+ /* Note +4 braindamage below is necessary because the FP
+ status registers are internally 8 registers rather than
+ the expected 4 registers. */
+ saved_fr_mask &= ~(1 << reg);
+ if (fp_loc == -1)
+ {
+ /* 1st HP CC FP register store. After this
+ instruction we've set enough state that the GCC and
+ HPCC code are both handled in the same manner. */
+ cache->saved_regs[reg + HPPA_FP4_REGNUM + 4].addr = 0;
+ fp_loc = 8;
+ }
+ else
+ {
+ cache->saved_regs[reg + HPPA_FP0_REGNUM + 4].addr = fp_loc;
+ fp_loc += 8;
+ }
+ }
+
+ /* Quit if we hit any kind of branch the previous iteration. */
+ if (final_iteration)
+ break;
+ /* We want to look precisely one instruction beyond the branch
+ if we have not found everything yet. */
+ if (is_branch (inst))
+ final_iteration = 1;
+ }
+ }
+
+ {
+ /* The frame base always represents the value of %sp at entry to
+ 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, "
+ "prologue_end=0x%s) ",
+ paddr_nz (this_sp),
+ paddr_nz (frame_pc_unwind (next_frame)),
+ paddr_nz (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.
+
+ fp may be zero if it is not available in an inner frame because
+ it has been modified by not yet saved.
+
+ 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 (frame_pc_unwind (next_frame) >= prologue_end
+ && u->Save_SP && 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))
+ {
+ /* 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);
+
+ if (hppa_debug)
+ 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));
+
+ }
+ trad_frame_set_value (cache->saved_regs, HPPA_SP_REGNUM, cache->base);
+ }
+
+ /* The PC is found in the "return register", "Millicode" uses "r31"
+ as the return register while normal code uses "rp". */
+ if (u->Millicode)
+ {
+ if (trad_frame_addr_p (cache->saved_regs, 31))
+ cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[31];
+ else
+ {
+ ULONGEST r31 = frame_unwind_register_unsigned (next_frame, 31);
+ trad_frame_set_value (cache->saved_regs, HPPA_PCOQ_HEAD_REGNUM, r31);
+ }
+ }
+ 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];
+ 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 the frame pointer was not saved in this frame, but we should be saving
+ it, set it to an invalid value so that another frame will not pick up the
+ wrong frame pointer. This can happen if we start unwinding after the
+ frame pointer has been modified, but before we've saved it to the
+ stack. */
+ if (u->Save_SP && !trad_frame_addr_p (cache->saved_regs, HPPA_FP_REGNUM))
+ trad_frame_set_value (cache->saved_regs, HPPA_FP_REGNUM, 0);
+
+ {
+ /* Convert all the offsets into addresses. */
+ int reg;
+ for (reg = 0; reg < NUM_REGS; reg++)
+ {
+ if (trad_frame_addr_p (cache->saved_regs, reg))
+ cache->saved_regs[reg].addr += cache->base;
+ }
+ }
+
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "base=0x%s }",
+ paddr_nz (((struct hppa_frame_cache *)*this_cache)->base));
+ return (*this_cache);
+}
+
+static void
+hppa_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ 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 = find_unwind_entry (pc);
+
+ (*this_id) = frame_id_build (info->base, u->region_start);
}
+static void
+hppa_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct hppa_frame_cache *info = hppa_frame_cache (next_frame, this_cache);
+ hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind hppa_frame_unwind =
+{
+ NORMAL_FRAME,
+ hppa_frame_this_id,
+ hppa_frame_prev_register
+};
+
+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))
+ return &hppa_frame_unwind;
+
+ return NULL;
+}
+
+/* This is a generic fallback frame unwinder that kicks in if we fail all
+ the other ones. Normally we would expect the stub and regular unwinder
+ to work, but in some cases we might hit a function that just doesn't
+ have any unwind information available. In this case we try to do
+ unwinding solely based on code reading. This is obviously going to be
+ slow, so only use this as a last resort. Currently this will only
+ identify the stack and pc for the frame. */
+
static struct hppa_frame_cache *
-hppa32_frame_cache (struct frame_info *next_frame, void **this_cache)
+hppa_fallback_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct hppa_frame_cache *cache;
- int regnum;
+ unsigned int frame_size;
+ int found_rp;
+ CORE_ADDR pc, start_pc, end_pc, cur_pc;
- if (*this_cache)
- return *this_cache;
+ if (hppa_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ hppa_fallback_frame_cache (frame=%d)-> ",
+ frame_relative_level(next_frame));
- /* Allocate a new cache. */
cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
+ (*this_cache) = cache;
cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
- cache->frame_size = 0;
- cache->pc = frame_func_unwind (next_frame);
- if (cache->pc != 0)
+ pc = frame_func_unwind (next_frame);
+ cur_pc = frame_pc_unwind (next_frame);
+ frame_size = 0;
+ found_rp = 0;
+
+ find_pc_partial_function (pc, NULL, &start_pc, &end_pc);
+
+ if (start_pc == 0 || end_pc == 0)
{
- CORE_ADDR addr_in_block = frame_unwind_address_in_block (next_frame);
- hppa32_analyze_prologue (cache->pc, addr_in_block, cache);
+ error ("Cannot find bounds of current function (@0x%s), unwinding will "
+ "fail.", paddr_nz (pc));
+ return cache;
}
- /* Calculate this frame's base. */
- gdb_assert (trad_frame_realreg_p (cache->saved_regs, HPPA_SP_REGNUM));
- regnum = cache->saved_regs[HPPA_SP_REGNUM].realreg;
- cache->base = frame_unwind_register_unsigned (next_frame, regnum);
- if (cache->frame_size > 0)
+ if (end_pc > cur_pc)
+ end_pc = cur_pc;
+
+ for (pc = start_pc; pc < end_pc; pc += 4)
{
- cache->base -= cache->frame_size;
- trad_frame_set_value (cache->saved_regs, HPPA_SP_REGNUM, cache->base);
+ unsigned int insn;
+
+ 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;
+ found_rp = 1;
+ }
+ else if (insn == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
+ {
+ cache->saved_regs[HPPA_RP_REGNUM].addr = -16;
+ found_rp = 1;
+ }
}
- for (regnum = HPPA_R1_REGNUM; regnum < HPPA32_NUM_REGS; regnum++)
+ 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) - 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))
{
- if (trad_frame_addr_p (cache->saved_regs, regnum))
- cache->saved_regs[regnum].addr += cache->base;
+ cache->saved_regs[HPPA_RP_REGNUM].addr += cache->base;
+ 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);
+ trad_frame_set_value (cache->saved_regs, HPPA_PCOQ_HEAD_REGNUM, rp);
}
- /* Identify the head of the program counter offset queue (%pcoqh)
- with the return pointer (%rp). */
- cache->saved_regs[HPPA_PCOQ_HEAD_REGNUM] = cache->saved_regs[HPPA_RP_REGNUM];
-
- *this_cache = cache;
return cache;
}
static void
-hppa32_frame_this_id (struct frame_info *next_frame, void **this_cache,
- struct frame_id *this_id)
+hppa_fallback_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
{
- struct hppa_frame_cache *cache =
- hppa32_frame_cache (next_frame, this_cache);
+ 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 marks the outermost frame. */
- if (cache->base == 0)
- return;
+static void
+hppa_fallback_frame_prev_register (struct frame_info *next_frame,
+ void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ struct hppa_frame_cache *info =
+ hppa_fallback_frame_cache (next_frame, this_cache);
+ hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind hppa_fallback_frame_unwind =
+{
+ NORMAL_FRAME,
+ hppa_fallback_frame_this_id,
+ hppa_fallback_frame_prev_register
+};
- (*this_id) = frame_id_build (cache->base, cache->pc);
+static const struct frame_unwind *
+hppa_fallback_unwind_sniffer (struct frame_info *next_frame)
+{
+ return &hppa_fallback_frame_unwind;
}
-static void
-hppa32_frame_prev_register (struct frame_info *next_frame, void **this_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+/* Stub frames, used for all kinds of call stubs. */
+struct hppa_stub_unwind_cache
+{
+ CORE_ADDR base;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+static struct hppa_stub_unwind_cache *
+hppa_stub_frame_unwind_cache (struct frame_info *next_frame,
+ void **this_cache)
{
- struct hppa_frame_cache *cache =
- hppa32_frame_cache (next_frame, this_cache);
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct hppa_stub_unwind_cache *info;
+ struct unwind_table_entry *u;
- if (regnum == HPPA_PCOQ_TAIL_REGNUM)
+ if (*this_cache)
+ return *this_cache;
+
+ info = FRAME_OBSTACK_ZALLOC (struct hppa_stub_unwind_cache);
+ *this_cache = info;
+ info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ info->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+
+ if (gdbarch_osabi (gdbarch) == GDB_OSABI_HPUX_SOM)
{
- if (valuep)
- {
- CORE_ADDR pc;
+ /* 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));
- /* Fetch the head of the program counter offset queue
- (%pcoqh). */
- trad_frame_prev_register (next_frame, cache->saved_regs,
- HPPA_PCOQ_HEAD_REGNUM, optimizedp,
- lvalp, addrp, realnump, valuep);
+ if (u && u->stub_unwind.stub_type == EXPORT)
+ {
+ info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].addr = info->base - 24;
- /* Now compute its tail (%pcoqt) by adding four bytes such
- that it points at the next instruction. */
- pc = extract_unsigned_integer (valuep, 4);
- store_unsigned_integer (valuep, 4, pc + 4);
+ return info;
}
-
- /* It's a computed value. */
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- return;
}
- trad_frame_prev_register (next_frame, cache->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ /* By default we assume that stubs do not change the rp. */
+ info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].realreg = HPPA_RP_REGNUM;
+
+ return info;
+}
+
+static void
+hppa_stub_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
+{
+ 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));
}
-static const struct frame_unwind hppa32_frame_unwind =
+static void
+hppa_stub_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *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);
+}
+
+static const struct frame_unwind hppa_stub_frame_unwind = {
NORMAL_FRAME,
- hppa32_frame_this_id,
- hppa32_frame_prev_register
+ hppa_stub_frame_this_id,
+ hppa_stub_frame_prev_register
};
static const struct frame_unwind *
-hppa32_frame_sniffer (struct frame_info *next_frame)
+hppa_stub_unwind_sniffer (struct frame_info *next_frame)
{
- return &hppa32_frame_unwind;
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+ if (pc == 0
+ || IN_SOLIB_CALL_TRAMPOLINE (pc, NULL)
+ || IN_SOLIB_RETURN_TRAMPOLINE (pc, NULL))
+ return &hppa_stub_frame_unwind;
+ return NULL;
+}
+
+static struct frame_id
+hppa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_id_build (frame_unwind_register_unsigned (next_frame,
+ HPPA_SP_REGNUM),
+ frame_pc_unwind (next_frame));
}
-
static CORE_ADDR
-hppa32_frame_base_address (struct frame_info *next_frame, void **this_cache)
+hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- struct hppa_frame_cache *cache =
- hppa32_frame_cache (next_frame, this_cache);
+ return frame_unwind_register_signed (next_frame, HPPA_PCOQ_HEAD_REGNUM) & ~3;
+}
- return cache->base;
+/* Instead of this nasty cast, add a method pvoid() that prints out a
+ host VOID data type (remember %p isn't portable). */
+
+static CORE_ADDR
+hppa_pointer_to_address_hack (void *ptr)
+{
+ gdb_assert (sizeof (ptr) == TYPE_LENGTH (builtin_type_void_data_ptr));
+ return POINTER_TO_ADDRESS (builtin_type_void_data_ptr, &ptr);
}
-static const struct frame_base hppa32_frame_base =
+static void
+unwind_command (char *exp, int from_tty)
{
- &hppa32_frame_unwind,
- hppa32_frame_base_address,
- hppa32_frame_base_address,
- hppa32_frame_base_address
-};
-
+ CORE_ADDR address;
+ struct unwind_table_entry *u;
+
+ /* If we have an expression, evaluate it and use it as the address. */
+
+ if (exp != 0 && *exp != 0)
+ address = parse_and_eval_address (exp);
+ else
+ return;
+
+ u = find_unwind_entry (address);
+
+ if (!u)
+ {
+ printf_unfiltered ("Can't find unwind table entry for %s\n", exp);
+ return;
+ }
+
+ printf_unfiltered ("unwind_table_entry (0x%s):\n",
+ paddr_nz (hppa_pointer_to_address_hack (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);
+
+ printf_unfiltered ("\n\tflags =");
+ pif (Cannot_unwind);
+ pif (Millicode);
+ pif (Millicode_save_sr0);
+ pif (Entry_SR);
+ pif (Args_stored);
+ pif (Variable_Frame);
+ pif (Separate_Package_Body);
+ pif (Frame_Extension_Millicode);
+ pif (Stack_Overflow_Check);
+ pif (Two_Instruction_SP_Increment);
+ pif (Ada_Region);
+ pif (Save_SP);
+ pif (Save_RP);
+ pif (Save_MRP_in_frame);
+ pif (extn_ptr_defined);
+ pif (Cleanup_defined);
+ pif (MPE_XL_interrupt_marker);
+ pif (HP_UX_interrupt_marker);
+ pif (Large_frame);
+
+ putchar_unfiltered ('\n');
+
+#define pin(FLD) printf_unfiltered ("\t"#FLD" = 0x%x\n", u->FLD);
+
+ pin (Region_description);
+ 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. */
+}
+
+int
+hppa_pc_requires_run_before_use (CORE_ADDR pc)
+{
+ /* Sometimes we may pluck out a minimal symbol that has a negative address.
+
+ An example of this occurs when an a.out is linked against a foo.sl.
+ The foo.sl defines a global bar(), and the a.out declares a signature
+ for bar(). However, the a.out doesn't directly call bar(), but passes
+ its address in another call.
+
+ If you have this scenario and attempt to "break bar" before running,
+ gdb will find a minimal symbol for bar() in the a.out. But that
+ symbol's address will be negative. What this appears to denote is
+ an index backwards from the base of the procedure linkage table (PLT)
+ into the data linkage table (DLT), the end of which is contiguous
+ with the start of the PLT. This is clearly not a valid address for
+ us to set a breakpoint on.
+
+ Note that one must be careful in how one checks for a negative address.
+ 0xc0000000 is a legitimate address of something in a shared text
+ segment, for example. Since I don't know what the possible range
+ is of these "really, truly negative" addresses that come from the
+ 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 the GDB type object for the "standard" data type of data
+ in register N. */
+
+static struct type *
+hppa32_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+ if (reg_nr < HPPA_FP4_REGNUM)
+ return builtin_type_uint32;
+ else
+ return builtin_type_ieee_single_big;
+}
+
+/* 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)
+{
+ if (reg_nr < HPPA_FP4_REGNUM)
+ return builtin_type_uint64;
+ else
+ return builtin_type_ieee_double_big;
+}
+
+/* Return True if REGNUM is not a register available to the user
+ through ptrace(). */
+
+static int
+hppa_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 CORE_ADDR
+hppa_smash_text_address (CORE_ADDR addr)
+{
+ /* The low two bits of the PC on the PA contain the privilege level.
+ Some genius implementing a (non-GCC) compiler apparently decided
+ this means that "addresses" in a text section therefore include a
+ privilege level, and thus symbol tables should contain these bits.
+ This seems like a bonehead thing to do--anyway, it seems to work
+ for our purposes to just ignore those bits. */
+
+ return (addr &= ~0x3);
+}
+
+/* Get the ith function argument for the current function. */
+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;
+}
static void
-hppa_write_pc (CORE_ADDR pc, ptid_t ptid)
+hppa_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, void *buf)
{
- write_register_pid (HPPA_PCOQ_HEAD_REGNUM, pc, ptid);
- write_register_pid (HPPA_PCOQ_TAIL_REGNUM, pc + 4, ptid);
+ 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);
}
-
static CORE_ADDR
-hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+hppa_find_global_pointer (struct value *function)
{
- CORE_ADDR pc;
+ return 0;
+}
+
+void
+hppa_frame_prev_register_helper (struct frame_info *next_frame,
+ struct trad_frame_saved_reg saved_regs[],
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, void *valuep)
+{
+ if (regnum == HPPA_PCOQ_TAIL_REGNUM)
+ {
+ if (valuep)
+ {
+ CORE_ADDR pc;
- pc = frame_unwind_register_unsigned (next_frame, HPPA_PCOQ_HEAD_REGNUM);
- return hppa_addr_bits_remove (pc);
+ trad_frame_get_prev_register (next_frame, saved_regs,
+ HPPA_PCOQ_HEAD_REGNUM, optimizedp,
+ lvalp, addrp, realnump, valuep);
+
+ pc = extract_unsigned_integer (valuep, 4);
+ store_unsigned_integer (valuep, 4, pc + 4);
+ }
+
+ /* 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);
}
+/* 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:
+
+ /usr/ccs/bin/cc HP92453-01 A.11.01.21
+ /opt/ansic/bin/cc HP92453-01 B.11.11.28706.GP
+ /opt/aCC/bin/aCC B3910B A.03.45
+ gcc gcc 3.3.2 native hppa2.0w-hp-hpux11.11
+
+ cc : 1 2 4 4 8 : 4 8 -- : 4 4
+ ansic +DA1.1 : 1 2 4 4 8 : 4 8 16 : 4 4
+ ansic +DA2.0 : 1 2 4 4 8 : 4 8 16 : 4 4
+ ansic +DA2.0W : 1 2 4 8 8 : 4 8 16 : 8 8
+ acc +DA1.1 : 1 2 4 4 8 : 4 8 16 : 4 4
+ acc +DA2.0 : 1 2 4 4 8 : 4 8 16 : 4 4
+ acc +DA2.0W : 1 2 4 8 8 : 4 8 16 : 8 8
+ gcc : 1 2 4 4 8 : 4 8 16 : 4 4
+
+ Each line is:
+
+ compiler and options
+ char, short, int, long, long long
+ float, double, long double
+ char *, void (*)()
+
+ So all these compilers use either ILP32 or LP64 model.
+ TODO: gcc has more options so it needs more investigation.
+
+ For floating point types, see:
+
+ http://docs.hp.com/hpux/pdf/B3906-90006.pdf
+ HP-UX floating-point guide, hpux 11.00
+
+ -- chastain 2003-12-18 */
+
static struct gdbarch *
-hppa32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
+
+ /* Try to determine the ABI of the object we are loading. */
+ if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
+ {
+ /* If it's a SOM file, assume it's HP/UX SOM. */
+ if (bfd_get_flavour (info.abfd) == bfd_target_som_flavour)
+ info.osabi = GDB_OSABI_HPUX_SOM;
+ }
- /* If there is already a candidate, use it. */
+ /* find a candidate among the list of pre-declared architectures. */
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
- return arches->gdbarch;
+ return (arches->gdbarch);
- /* Allocate space for the new architecture. */
- tdep = XMALLOC (struct gdbarch_tdep);
+ /* If none found, then allocate and initialize one. */
+ tdep = XZALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
- set_gdbarch_long_double_bit (gdbarch, 128);
- set_gdbarch_long_double_format (gdbarch, &floatformat_hppa_quad);
+ /* Determine from the bfd_arch_info structure if we are dealing with
+ a 32 or 64 bits architecture. If the bfd_arch_info is not available,
+ then default to a 32bit machine. */
+ if (info.bfd_arch_info != NULL)
+ tdep->bytes_per_address =
+ info.bfd_arch_info->bits_per_address / info.bfd_arch_info->bits_per_byte;
+ else
+ tdep->bytes_per_address = 4;
- set_gdbarch_num_regs (gdbarch, HPPA32_NUM_REGS);
- set_gdbarch_register_name (gdbarch, hppa32_register_name);
- set_gdbarch_register_type (gdbarch, hppa32_register_type);
+ tdep->find_global_pointer = hppa_find_global_pointer;
- /* Register numbers of various important registers. */
- set_gdbarch_sp_regnum (gdbarch, HPPA_SP_REGNUM); /* %sp */
- set_gdbarch_pc_regnum (gdbarch, HPPA_PCOQ_HEAD_REGNUM); /* %pc */
+ /* 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)
+ {
+ case 4:
+ set_gdbarch_num_regs (gdbarch, hppa32_num_regs);
+ set_gdbarch_register_name (gdbarch, hppa32_register_name);
+ set_gdbarch_register_type (gdbarch, hppa32_register_type);
+ 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);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "Unsupported address size: %d",
+ tdep->bytes_per_address);
+ }
- set_gdbarch_addr_bits_remove (gdbarch, hppa_addr_bits_remove);
+ set_gdbarch_long_bit (gdbarch, tdep->bytes_per_address * TARGET_CHAR_BIT);
+ set_gdbarch_ptr_bit (gdbarch, tdep->bytes_per_address * TARGET_CHAR_BIT);
- set_gdbarch_skip_prologue (gdbarch, hppa32_skip_prologue);
+ /* The following gdbarch vector elements are the same in both ILP32
+ 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);
- /* Stack grows upward. */
+ /* 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_inner_than (gdbarch, core_addr_greaterthan);
-
- set_gdbarch_breakpoint_from_pc (gdbarch, hppa_breakpoint_from_pc);
+ 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);
+
+ /* Helper for function argument information. */
+ set_gdbarch_fetch_pointer_argument (gdbarch, hppa_fetch_pointer_argument);
set_gdbarch_print_insn (gdbarch, print_insn_hppa);
- set_gdbarch_unwind_pc (gdbarch, hppa_unwind_pc);
- set_gdbarch_write_pc (gdbarch, hppa_write_pc);
+ /* When a hardware watchpoint triggers, we'll move the inferior past
+ it by removing all eventpoints; stepping past the instruction
+ that caused the trigger; reinserting eventpoints; and checking
+ whether any watched location changed. */
+ set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
+ /* Inferior function call methods. */
+ switch (tdep->bytes_per_address)
+ {
+ 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");
+ }
+
+ /* Struct return methods. */
+ switch (tdep->bytes_per_address)
+ {
+ case 4:
+ set_gdbarch_return_value (gdbarch, hppa32_return_value);
+ break;
+ case 8:
+ set_gdbarch_return_value (gdbarch, hppa64_return_value);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "bad switch");
+ }
+
+ set_gdbarch_breakpoint_from_pc (gdbarch, hppa_breakpoint_from_pc);
+ set_gdbarch_pseudo_register_read (gdbarch, hppa_pseudo_register_read);
- frame_base_set_default (gdbarch, &hppa32_frame_base);
+ /* Frame unwind methods. */
+ set_gdbarch_unwind_dummy_id (gdbarch, hppa_unwind_dummy_id);
+ set_gdbarch_unwind_pc (gdbarch, hppa_unwind_pc);
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
- frame_unwind_append_sniffer (gdbarch, hppa32_frame_sniffer);
+ /* Hook in the default unwinders. */
+ 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);
return gdbarch;
}
-
-/* Provide a prototype to silence -Wmissing-prototypes. */
-void _initialize_hppa_tdep (void);
+static void
+hppa_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ fprintf_unfiltered (file, "bytes_per_address = %d\n",
+ tdep->bytes_per_address);
+ fprintf_unfiltered (file, "elf = %s\n", tdep->is_elf ? "yes" : "no");
+}
void
_initialize_hppa_tdep (void)
{
- register_gdbarch_init (bfd_arch_hppa, hppa32_gdbarch_init);
+ 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.",
+ &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. */
+ deprecated_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);
}