/* Target-dependent code for the HP PA architecture, for GDB.
Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ 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).
#include "osabi.h"
#include "gdb_assert.h"
#include "infttrace.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"
#ifdef USG
#include <sys/types.h>
#include "target.h"
#include "symfile.h"
#include "objfiles.h"
+#include "hppa-tdep.h"
/* Some local constants. */
-static const int hppa_num_regs = 128;
+static const int hppa32_num_regs = 128;
+static const int hppa64_num_regs = 96;
+
+static const int hppa64_call_dummy_breakpoint_offset = 22 * 4;
+
+/* DEPRECATED_CALL_DUMMY_LENGTH is computed based on the size of a
+ word on the target machine, not the size of an instruction. Since
+ a word on this target holds two instructions we have to divide the
+ instruction size by two to get the word size of the dummy. */
+static const int hppa32_call_dummy_length = INSTRUCTION_SIZE * 28;
+static const int hppa64_call_dummy_length = INSTRUCTION_SIZE * 26 / 2;
/* Get at various relevent fields of an instruction word. */
#define MASK_5 0x1f
static unsigned extract_5r_store (unsigned int);
+static void hppa_frame_init_saved_regs (struct frame_info *frame);
+
static void find_dummy_frame_regs (struct frame_info *, CORE_ADDR *);
static int find_proc_framesize (CORE_ADDR);
int hppa_in_solib_return_trampoline (CORE_ADDR pc, char *name);
CORE_ADDR hppa_saved_pc_after_call (struct frame_info *frame);
int hppa_inner_than (CORE_ADDR lhs, CORE_ADDR rhs);
-CORE_ADDR hppa_stack_align (CORE_ADDR sp);
+CORE_ADDR hppa32_stack_align (CORE_ADDR sp);
+CORE_ADDR hppa64_stack_align (CORE_ADDR sp);
int hppa_pc_requires_run_before_use (CORE_ADDR pc);
int hppa_instruction_nullified (void);
int hppa_register_raw_size (int reg_nr);
int hppa_register_byte (int reg_nr);
-struct type * hppa_register_virtual_type (int reg_nr);
+struct type * hppa32_register_virtual_type (int reg_nr);
+struct type * hppa64_register_virtual_type (int reg_nr);
void hppa_store_struct_return (CORE_ADDR addr, CORE_ADDR sp);
-void hppa_extract_return_value (struct type *type, char *regbuf, char *valbuf);
-int hppa_use_struct_convention (int gcc_p, struct type *type);
-void hppa_store_return_value (struct type *type, char *valbuf);
-CORE_ADDR hppa_extract_struct_value_address (char *regbuf);
+void hppa32_extract_return_value (struct type *type, char *regbuf,
+ char *valbuf);
+void hppa64_extract_return_value (struct type *type, char *regbuf,
+ char *valbuf);
+int hppa32_use_struct_convention (int gcc_p, struct type *type);
+int hppa64_use_struct_convention (int gcc_p, struct type *type);
+void hppa32_store_return_value (struct type *type, char *valbuf);
+void hppa64_store_return_value (struct type *type, char *valbuf);
int hppa_cannot_store_register (int regnum);
void hppa_init_extra_frame_info (int fromleaf, struct frame_info *frame);
CORE_ADDR hppa_frame_chain (struct frame_info *frame);
int hppa_frameless_function_invocation (struct frame_info *frame);
CORE_ADDR hppa_frame_saved_pc (struct frame_info *frame);
CORE_ADDR hppa_frame_args_address (struct frame_info *fi);
-CORE_ADDR hppa_frame_locals_address (struct frame_info *fi);
int hppa_frame_num_args (struct frame_info *frame);
void hppa_push_dummy_frame (void);
void hppa_pop_frame (void);
/* Should call_function allocate stack space for a struct return? */
int
-hppa_use_struct_convention (int gcc_p, struct type *type)
+hppa32_use_struct_convention (int gcc_p, struct type *type)
{
return (TYPE_LENGTH (type) > 2 * DEPRECATED_REGISTER_SIZE);
}
-\f
+
+/* Same as hppa32_use_struct_convention() for the PA64 ABI. */
+
+int
+hppa64_use_struct_convention (int gcc_p, struct type *type)
+{
+ /* RM: struct upto 128 bits are returned in registers */
+ return TYPE_LENGTH (type) > 16;
+}
/* Routines to extract various sized constants out of hppa
instructions. */
obj_private_data_t *obj_private;
text_offset = ANOFFSET (objfile->section_offsets, 0);
- ui = (struct obj_unwind_info *) obstack_alloc (&objfile->psymbol_obstack,
+ ui = (struct obj_unwind_info *) obstack_alloc (&objfile->objfile_obstack,
sizeof (struct obj_unwind_info));
ui->table = NULL;
/* Allocate memory for the unwind table. */
ui->table = (struct unwind_table_entry *)
- obstack_alloc (&objfile->psymbol_obstack, total_size);
+ obstack_alloc (&objfile->objfile_obstack, total_size);
ui->last = total_entries - 1;
/* Now read in each unwind section and internalize the standard unwind
if (objfile->obj_private == NULL)
{
obj_private = (obj_private_data_t *)
- obstack_alloc (&objfile->psymbol_obstack,
+ obstack_alloc (&objfile->objfile_obstack,
sizeof (obj_private_data_t));
obj_private->unwind_info = NULL;
obj_private->so_info = NULL;
const unsigned char *
hppa_breakpoint_from_pc (CORE_ADDR *pc, int *len)
{
- static const char breakpoint[] = {0x00, 0x01, 0x00, 0x04};
+ static const unsigned char breakpoint[] = {0x00, 0x01, 0x00, 0x04};
(*len) = sizeof (breakpoint);
return breakpoint;
}
/* Return the name of a register. */
const char *
-hppa_register_name (int i)
+hppa32_register_name (int i)
{
static char *names[] = {
"flags", "r1", "rp", "r3",
{
CORE_ADDR *saved_regs;
hppa_frame_init_saved_regs (get_next_frame (frame));
- saved_regs = get_frame_saved_regs (get_next_frame (frame));
+ saved_regs = deprecated_get_frame_saved_regs (get_next_frame (frame));
if (read_memory_integer (saved_regs[FLAGS_REGNUM],
TARGET_PTR_BIT / 8) & 0x2)
{
{
CORE_ADDR *saved_regs;
hppa_frame_init_saved_regs (get_next_frame (frame));
- saved_regs = get_frame_saved_regs (get_next_frame (frame));
+ saved_regs = deprecated_get_frame_saved_regs (get_next_frame (frame));
if (read_memory_integer (saved_regs[FLAGS_REGNUM],
TARGET_PTR_BIT / 8) & 0x2)
{
in optimized code, GCC often doesn't actually save r3.
We'll discover this if we look at the prologue. */
hppa_frame_init_saved_regs (tmp_frame);
- saved_regs = get_frame_saved_regs (tmp_frame);
+ saved_regs = deprecated_get_frame_saved_regs (tmp_frame);
saved_regs_frame = tmp_frame;
/* If we have an address for r3, that's good. */
if (tmp_frame != saved_regs_frame)
{
hppa_frame_init_saved_regs (tmp_frame);
- saved_regs = get_frame_saved_regs (tmp_frame);
+ saved_regs = deprecated_get_frame_saved_regs (tmp_frame);
}
/* Abominable hack. */
if (tmp_frame != saved_regs_frame)
{
hppa_frame_init_saved_regs (tmp_frame);
- saved_regs = get_frame_saved_regs (tmp_frame);
+ saved_regs = deprecated_get_frame_saved_regs (tmp_frame);
}
/* Abominable hack. See above. */
hppa_push_dummy_frame (void)
{
CORE_ADDR sp, pc, pcspace;
- register int regnum;
+ int regnum;
CORE_ADDR int_buffer;
double freg_buffer;
for (regnum = FP0_REGNUM; regnum < NUM_REGS; regnum++)
{
- deprecated_read_register_bytes (REGISTER_BYTE (regnum),
+ deprecated_read_register_bytes (DEPRECATED_REGISTER_BYTE (regnum),
(char *) &freg_buffer, 8);
sp = push_bytes (sp, (char *) &freg_buffer, 8);
}
void
hppa_pop_frame (void)
{
- register struct frame_info *frame = get_current_frame ();
- register CORE_ADDR fp, npc, target_pc;
- register int regnum;
+ struct frame_info *frame = get_current_frame ();
+ CORE_ADDR fp, npc, target_pc;
+ int regnum;
CORE_ADDR *fsr;
double freg_buffer;
fp = get_frame_base (frame);
hppa_frame_init_saved_regs (frame);
- fsr = get_frame_saved_regs (frame);
+ fsr = deprecated_get_frame_saved_regs (frame);
#ifndef NO_PC_SPACE_QUEUE_RESTORE
if (fsr[IPSW_REGNUM]) /* Restoring a call dummy frame */
if (fsr[regnum])
{
read_memory (fsr[regnum], (char *) &freg_buffer, 8);
- deprecated_write_register_bytes (REGISTER_BYTE (regnum),
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (regnum),
(char *) &freg_buffer, 8);
}
/* The value of SP as it was passed into this function after
aligning. */
- CORE_ADDR orig_sp = STACK_ALIGN (sp);
+ CORE_ADDR orig_sp = DEPRECATED_STACK_ALIGN (sp);
/* The number of stack bytes occupied by the current argument. */
int bytes_reserved;
The ABIs also mandate minimum stack alignments which we must
preserve. */
- cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
+ cum_bytes_aligned = DEPRECATED_STACK_ALIGN (cum_bytes_reserved);
sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
/* Now write each of the args at the proper offset down the stack. */
The ABI also mandates minimum stack alignments which we must
preserve. */
- cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
+ cum_bytes_aligned = DEPRECATED_STACK_ALIGN (cum_bytes_reserved);
sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
/* Now write each of the args at the proper offset down the stack.
#endif
-/* elz: this function returns a value which is built looking at the given address.
- It is called from call_function_by_hand, in case we need to return a
- value which is larger than 64 bits, and it is stored in the stack rather than
- in the registers r28 and r29 or fr4.
- This function does the same stuff as value_being_returned in values.c, but
- gets the value from the stack rather than from the buffer where all the
- registers were saved when the function called completed. */
-struct value *
-hppa_value_returned_from_stack (register struct type *valtype, CORE_ADDR addr)
-{
- register struct value *val;
-
- val = allocate_value (valtype);
- CHECK_TYPEDEF (valtype);
- target_read_memory (addr, VALUE_CONTENTS_RAW (val), TYPE_LENGTH (valtype));
-
- return val;
-}
-
-
-
/* elz: Used to lookup a symbol in the shared libraries.
This function calls shl_findsym, indirectly through a
call to __d_shl_get. __d_shl_get is in end.c, which is always
{
stub_symbol
= lookup_minimal_symbol_solib_trampoline
- (DEPRECATED_SYMBOL_NAME (funsymbol), NULL, objfile);
+ (DEPRECATED_SYMBOL_NAME (funsymbol), objfile);
if (!stub_symbol)
stub_symbol = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (funsymbol),
write_register_pid (31, v | 0x3, ptid);
write_register_pid (PC_REGNUM, v, ptid);
- write_register_pid (NPC_REGNUM, v + 4, ptid);
+ write_register_pid (PCOQ_TAIL_REGNUM, v + 4, ptid);
}
/* return the alignment of a type in bytes. Structures have the maximum
/* Make a copy of gdb's save area (may cause actual
reads from the target). */
for (i = 0; i < NUM_REGS; i++)
- frame_register_read (deprecated_selected_frame, i, raw_regs + REGISTER_BYTE (i));
+ frame_register_read (deprecated_selected_frame, i,
+ raw_regs + DEPRECATED_REGISTER_BYTE (i));
if (regnum == -1)
pa_print_registers (raw_regs, regnum, fpregs);
/* Make a copy of gdb's save area (may cause actual
reads from the target). */
for (i = 0; i < NUM_REGS; i++)
- frame_register_read (deprecated_selected_frame, i, raw_regs + REGISTER_BYTE (i));
+ frame_register_read (deprecated_selected_frame, i,
+ raw_regs + DEPRECATED_REGISTER_BYTE (i));
if (regnum == -1)
pa_strcat_registers (raw_regs, regnum, fpregs, stream);
int regaddr;
unsigned int offset;
- register int i;
+ int i;
int start;
if (!is_pa_2)
{
- raw_val[1] = *(long *) (raw_regs + REGISTER_BYTE (regnum));
+ raw_val[1] = *(long *) (raw_regs + DEPRECATED_REGISTER_BYTE (regnum));
return;
}
frame_register_read (deprecated_selected_frame, i, raw_buffer);
/* Put it in the buffer. No conversions are ever necessary. */
- memcpy (virtual_buffer, raw_buffer, REGISTER_RAW_SIZE (i));
+ memcpy (virtual_buffer, raw_buffer, DEPRECATED_REGISTER_RAW_SIZE (i));
fputs_filtered (REGISTER_NAME (i), gdb_stdout);
print_spaces_filtered (8 - strlen (REGISTER_NAME (i)), gdb_stdout);
fputs_filtered ("(single precision) ", gdb_stdout);
- val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, gdb_stdout, 0,
+ val_print (DEPRECATED_REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, gdb_stdout, 0,
1, 0, Val_pretty_default);
printf_filtered ("\n");
frame_register_read (deprecated_selected_frame, i + 1, raw_buffer);
/* Copy it into the appropriate part of the virtual buffer. */
- memcpy (virtual_buffer + REGISTER_RAW_SIZE (i), raw_buffer,
- REGISTER_RAW_SIZE (i));
+ memcpy (virtual_buffer + DEPRECATED_REGISTER_RAW_SIZE (i), raw_buffer,
+ DEPRECATED_REGISTER_RAW_SIZE (i));
/* Dump it as a double. */
fputs_filtered (REGISTER_NAME (i), gdb_stdout);
frame_register_read (deprecated_selected_frame, i, raw_buffer);
/* Put it in the buffer. No conversions are ever necessary. */
- memcpy (virtual_buffer, raw_buffer, REGISTER_RAW_SIZE (i));
+ memcpy (virtual_buffer, raw_buffer, DEPRECATED_REGISTER_RAW_SIZE (i));
if (precision == double_precision && (i % 2) == 0)
{
frame_register_read (deprecated_selected_frame, i + 1, raw_buf);
/* Copy it into the appropriate part of the virtual buffer. */
- memcpy (virtual_buffer + REGISTER_RAW_SIZE (i), raw_buf, REGISTER_RAW_SIZE (i));
+ memcpy (virtual_buffer + DEPRECATED_REGISTER_RAW_SIZE (i), raw_buf,
+ DEPRECATED_REGISTER_RAW_SIZE (i));
val_print (builtin_type_double, virtual_buffer, 0, 0, stream, 0,
1, 0, Val_pretty_default);
}
else
{
- val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, stream, 0,
+ val_print (DEPRECATED_REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, 0, stream, 0,
1, 0, Val_pretty_default);
}
sec = SYMBOL_BFD_SECTION (minsym);
- if (sec->vma <= pc
- && sec->vma + sec->_cooked_size < pc)
+ if (bfd_get_section_vma (sec->owner, sec) <= pc
+ && pc < (bfd_get_section_vma (sec->owner, sec)
+ + bfd_section_size (sec->owner, sec)))
return 0;
/* We might be in a stub. Peek at the instructions. Stubs are 3
ALL_MSYMBOLS (objfile, msymbol)
{
if (MSYMBOL_TYPE (msymbol) == mst_text
- && STREQ (DEPRECATED_SYMBOL_NAME (msymbol), DEPRECATED_SYMBOL_NAME (msym)))
+ && DEPRECATED_STREQ (DEPRECATED_SYMBOL_NAME (msymbol), DEPRECATED_SYMBOL_NAME (msym)))
{
function_found = 1;
break;
&& extract_14 (inst) >= 0)
frame_saved_regs[reg] = get_frame_base (frame_info);
/* A std has explicit post_modify forms. */
- else if ((inst & 0xfc00000c0) == 0x70000008)
+ else if ((inst & 0xfc00000c) == 0x70000008)
frame_saved_regs[reg] = get_frame_base (frame_info);
else
{
that do not yet implement DEPRECATED_FRAME_INIT_SAVED_REGS. */
/* Find the addresses in which registers are saved in FRAME. */
-void
+static void
hppa_frame_init_saved_regs (struct frame_info *frame)
{
- if (get_frame_saved_regs (frame) == NULL)
+ if (deprecated_get_frame_saved_regs (frame) == NULL)
frame_saved_regs_zalloc (frame);
- hppa_frame_find_saved_regs (frame, get_frame_saved_regs (frame));
+ hppa_frame_find_saved_regs (frame, deprecated_get_frame_saved_regs (frame));
+}
+
+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;
+ int i;
+
+ if ((*this_cache) != NULL)
+ return (*this_cache);
+ cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
+ (*this_cache) = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ /* Yow! */
+ u = find_unwind_entry (frame_func_unwind (next_frame));
+ if (!u)
+ return;
+
+ /* 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 == DEPRECATED_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;
+ CORE_ADDR end_pc = skip_prologue_using_sal (pc);
+ int looking_for_sp = u->Save_SP;
+ int looking_for_rp = u->Save_RP;
+ int fp_loc = -1;
+ if (end_pc == 0)
+ end_pc = frame_pc_unwind (next_frame);
+ frame_size = 0;
+ for (pc = frame_func_unwind (next_frame);
+ ((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 = target_read_memory (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[RP_REGNUM].addr = -20;
+ }
+ else if (inst == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
+ {
+ looking_for_rp = 0;
+ cache->saved_regs[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[DEPRECATED_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 != DEPRECATED_FP_REGNUM))
+ {
+ saved_gr_mask &= ~(1 << reg);
+ if ((inst >> 26) == 0x1b && 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 = low_sign_extend (inst & 0x1f, 5);
+ else
+ offset = 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 = 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 + FP4_REGNUM + 4].addr = 0;
+ fp_loc = 8;
+ }
+ else
+ {
+ cache->saved_regs[reg + 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, SP_REGNUM);
+ /* FIXME: cagney/2004-02-22: This assumes that the frame has been
+ created. If it hasn't everything will be out-of-wack. */
+ if (u->Save_SP && trad_frame_addr_p (cache->saved_regs, 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);
+ else
+ /* The prologue has been slowly allocating stack space. Adjust
+ the SP back. */
+ cache->base = this_sp - frame_size;
+ trad_frame_set_value (cache->saved_regs, SP_REGNUM, cache->base);
+ }
+
+ /* The PC is found in the "return register". */
+ if (u->Millicode)
+ cache->saved_regs[PC_REGNUM] = cache->saved_regs[31];
+ else
+ cache->saved_regs[PC_REGNUM] = cache->saved_regs[RP_REGNUM];
+
+ {
+ /* 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;
+ }
+ }
+
+ 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 = hppa_frame_cache (next_frame, this_cache);
+ (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+}
+
+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);
+ trad_frame_prev_register (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)
+{
+ return &hppa_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;
+}
+
+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,
+ SP_REGNUM),
+ frame_pc_unwind (next_frame));
+}
+
+static CORE_ADDR
+hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_signed (next_frame, PC_REGNUM) & ~3;
}
/* Exception handling support for the HP-UX ANSI C++ compiler.
Called only in the context of the "return" command. */
void
-hppa_store_return_value (struct type *type, char *valbuf)
+hppa32_store_return_value (struct type *type, char *valbuf)
{
/* For software floating point, the return value goes into the
integer registers. But we do not have any flag to key this on,
If its a float value, then we also store it into the floating
point registers. */
- deprecated_write_register_bytes (REGISTER_BYTE (28)
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (28)
+ (TYPE_LENGTH (type) > 4
? (8 - TYPE_LENGTH (type))
: (4 - TYPE_LENGTH (type))),
valbuf, TYPE_LENGTH (type));
if (TYPE_CODE (type) == TYPE_CODE_FLT)
- deprecated_write_register_bytes (REGISTER_BYTE (FP4_REGNUM),
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (FP4_REGNUM),
valbuf, TYPE_LENGTH (type));
}
+/* Same as hppa32_store_return_value(), but for the PA64 ABI. */
+
+void
+hppa64_store_return_value (struct type *type, char *valbuf)
+{
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ deprecated_write_register_bytes
+ (DEPRECATED_REGISTER_BYTE (FP4_REGNUM)
+ + DEPRECATED_REGISTER_SIZE - TYPE_LENGTH (type),
+ valbuf, TYPE_LENGTH (type));
+ else if (is_integral_type(type))
+ deprecated_write_register_bytes
+ (DEPRECATED_REGISTER_BYTE (28)
+ + DEPRECATED_REGISTER_SIZE - TYPE_LENGTH (type),
+ valbuf, TYPE_LENGTH (type));
+ else if (TYPE_LENGTH (type) <= 8)
+ deprecated_write_register_bytes
+ (DEPRECATED_REGISTER_BYTE (28),valbuf, TYPE_LENGTH (type));
+ else if (TYPE_LENGTH (type) <= 16)
+ {
+ deprecated_write_register_bytes (DEPRECATED_REGISTER_BYTE (28),valbuf, 8);
+ deprecated_write_register_bytes
+ (DEPRECATED_REGISTER_BYTE (29), valbuf + 8, TYPE_LENGTH (type) - 8);
+ }
+}
+
/* Copy the function's return value into VALBUF.
This function is called only in the context of "target function calls",
"return" command. */
void
-hppa_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+hppa32_extract_return_value (struct type *type, char *regbuf, char *valbuf)
{
if (TYPE_CODE (type) == TYPE_CODE_FLT)
- memcpy (valbuf,
- (char *)regbuf + REGISTER_BYTE (FP4_REGNUM),
- TYPE_LENGTH (type));
+ memcpy (valbuf, regbuf + DEPRECATED_REGISTER_BYTE (FP4_REGNUM), TYPE_LENGTH (type));
else
memcpy (valbuf,
- ((char *)regbuf
- + REGISTER_BYTE (28)
+ (regbuf
+ + DEPRECATED_REGISTER_BYTE (28)
+ (TYPE_LENGTH (type) > 4
? (8 - TYPE_LENGTH (type))
: (4 - TYPE_LENGTH (type)))),
TYPE_LENGTH (type));
}
+/* Same as hppa32_extract_return_value but for the PA64 ABI case. */
+
+void
+hppa64_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+ /* 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)
+ memcpy (valbuf,
+ regbuf + DEPRECATED_REGISTER_BYTE (FP4_REGNUM)
+ + DEPRECATED_REGISTER_SIZE - TYPE_LENGTH (type),
+ TYPE_LENGTH (type));
+ else if (is_integral_type(type))
+ memcpy (valbuf,
+ regbuf + DEPRECATED_REGISTER_BYTE (28)
+ + DEPRECATED_REGISTER_SIZE - TYPE_LENGTH (type),
+ TYPE_LENGTH (type));
+ else if (TYPE_LENGTH (type) <= 8)
+ memcpy (valbuf, regbuf + DEPRECATED_REGISTER_BYTE (28),
+ TYPE_LENGTH (type));
+ else if (TYPE_LENGTH (type) <= 16)
+ {
+ memcpy (valbuf, regbuf + DEPRECATED_REGISTER_BYTE (28), 8);
+ memcpy (valbuf + 8, regbuf + DEPRECATED_REGISTER_BYTE (29),
+ TYPE_LENGTH (type) - 8);
+ }
+}
+
int
hppa_reg_struct_has_addr (int gcc_p, struct type *type)
{
}
CORE_ADDR
-hppa_stack_align (CORE_ADDR sp)
+hppa32_stack_align (CORE_ADDR sp)
{
/* elz: adjust the quantity to the next highest value which is
64-bit aligned. This is used in valops.c, when the sp is adjusted.
return ((sp % 8) ? (sp + 7) & -8 : sp);
}
+CORE_ADDR
+hppa64_stack_align (CORE_ADDR sp)
+{
+ /* The PA64 ABI mandates a 16 byte stack alignment. */
+ return ((sp % 16) ? (sp + 15) & -16 : sp);
+}
+
int
hppa_pc_requires_run_before_use (CORE_ADDR pc)
{
int
hppa_register_byte (int reg_nr)
{
- return reg_nr * 4;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ return reg_nr * tdep->bytes_per_address;
}
/* Return the GDB type object for the "standard" data type of data
in register N. */
struct type *
-hppa_register_virtual_type (int reg_nr)
+hppa32_register_virtual_type (int reg_nr)
{
if (reg_nr < FP4_REGNUM)
return builtin_type_int;
return builtin_type_float;
}
+/* Return the GDB type object for the "standard" data type of data
+ in register N. hppa64 version. */
+
+struct type *
+hppa64_register_virtual_type (int reg_nr)
+{
+ if (reg_nr < FP4_REGNUM)
+ return builtin_type_unsigned_long_long;
+ else
+ return builtin_type_double;
+}
+
/* Store the address of the place in which to copy the structure the
subroutine will return. This is called from call_function. */
{
write_register (28, addr);
}
-
-CORE_ADDR
-hppa_extract_struct_value_address (char *regbuf)
-{
- /* Extract from an array REGBUF containing the (raw) register state
- the address in which a function should return its structure value,
- as a CORE_ADDR (or an expression that can be used as one). */
- /* FIXME: brobecker 2002-12-26.
- The current implementation is historical, but we should eventually
- implement it in a more robust manner as it relies on the fact that
- the address size is equal to the size of an int* _on the host_...
- One possible implementation that crossed my mind is to use
- extract_address. */
- return (*(int *)(regbuf + REGISTER_BYTE (28)));
-}
-
/* Return True if REGNUM is not a register available to the user
through ptrace(). */
struct type *type)
{
CORE_ADDR addr;
- frame_read_register (frame, R0_REGNUM + 26 - argi, &addr);
+ get_frame_register (frame, R0_REGNUM + 26 - argi, &addr);
return addr;
}
+/* 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 *
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. */
return (arches->gdbarch);
/* If none found, then allocate and initialize one. */
- gdbarch = gdbarch_alloc (&info, NULL);
+ tdep = XMALLOC (struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ /* 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;
- /* Hook in ABI-specific overrides, if they have been registered. */
- gdbarch_init_osabi (info, gdbarch);
+ /* 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_deprecated_register_virtual_type
+ (gdbarch, hppa32_register_virtual_type);
+ break;
+ case 8:
+ set_gdbarch_num_regs (gdbarch, hppa64_num_regs);
+ set_gdbarch_register_name (gdbarch, hppa64_register_name);
+ set_gdbarch_deprecated_register_virtual_type
+ (gdbarch, hppa64_register_virtual_type);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "Unsupported address size: %d",
+ tdep->bytes_per_address);
+ }
- set_gdbarch_reg_struct_has_addr (gdbarch, hppa_reg_struct_has_addr);
- set_gdbarch_function_start_offset (gdbarch, 0);
+ /* The following gdbarch vector elements depend on other parts of this
+ vector which have been set above, depending on the ABI. */
+ set_gdbarch_deprecated_register_bytes
+ (gdbarch, gdbarch_num_regs (gdbarch) * tdep->bytes_per_address);
+ set_gdbarch_long_bit (gdbarch, tdep->bytes_per_address * TARGET_CHAR_BIT);
+ set_gdbarch_ptr_bit (gdbarch, tdep->bytes_per_address * TARGET_CHAR_BIT);
+
+ /* 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);
+
+ /* 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_skip_trampoline_code (gdbarch, hppa_skip_trampoline_code);
set_gdbarch_in_solib_call_trampoline (gdbarch, hppa_in_solib_call_trampoline);
set_gdbarch_in_solib_return_trampoline (gdbarch,
hppa_in_solib_return_trampoline);
- set_gdbarch_deprecated_saved_pc_after_call (gdbarch, hppa_saved_pc_after_call);
set_gdbarch_inner_than (gdbarch, hppa_inner_than);
- set_gdbarch_stack_align (gdbarch, hppa_stack_align);
- set_gdbarch_decr_pc_after_break (gdbarch, 0);
- set_gdbarch_deprecated_register_size (gdbarch, 4);
- set_gdbarch_num_regs (gdbarch, hppa_num_regs);
+ set_gdbarch_deprecated_register_size (gdbarch, tdep->bytes_per_address);
set_gdbarch_deprecated_fp_regnum (gdbarch, 3);
set_gdbarch_sp_regnum (gdbarch, 30);
set_gdbarch_fp0_regnum (gdbarch, 64);
set_gdbarch_pc_regnum (gdbarch, PCOQ_HEAD_REGNUM);
- set_gdbarch_npc_regnum (gdbarch, PCOQ_TAIL_REGNUM);
set_gdbarch_deprecated_register_raw_size (gdbarch, hppa_register_raw_size);
- set_gdbarch_deprecated_register_bytes (gdbarch, hppa_num_regs * 4);
set_gdbarch_deprecated_register_byte (gdbarch, hppa_register_byte);
set_gdbarch_deprecated_register_virtual_size (gdbarch, hppa_register_raw_size);
- set_gdbarch_deprecated_max_register_raw_size (gdbarch, 4);
+ set_gdbarch_deprecated_max_register_raw_size (gdbarch, tdep->bytes_per_address);
set_gdbarch_deprecated_max_register_virtual_size (gdbarch, 8);
- set_gdbarch_deprecated_register_virtual_type (gdbarch, hppa_register_virtual_type);
- set_gdbarch_register_name (gdbarch, hppa_register_name);
- set_gdbarch_deprecated_store_struct_return (gdbarch, hppa_store_struct_return);
- set_gdbarch_deprecated_extract_return_value (gdbarch,
- hppa_extract_return_value);
- set_gdbarch_use_struct_convention (gdbarch, hppa_use_struct_convention);
- set_gdbarch_deprecated_store_return_value (gdbarch, hppa_store_return_value);
- set_gdbarch_deprecated_extract_struct_value_address
- (gdbarch, hppa_extract_struct_value_address);
set_gdbarch_cannot_store_register (gdbarch, hppa_cannot_store_register);
- set_gdbarch_deprecated_init_extra_frame_info (gdbarch, hppa_init_extra_frame_info);
- set_gdbarch_deprecated_frame_chain (gdbarch, hppa_frame_chain);
- set_gdbarch_deprecated_frame_chain_valid (gdbarch, hppa_frame_chain_valid);
- set_gdbarch_frameless_function_invocation
- (gdbarch, hppa_frameless_function_invocation);
- set_gdbarch_deprecated_frame_saved_pc (gdbarch, hppa_frame_saved_pc);
- set_gdbarch_frame_args_skip (gdbarch, 0);
- set_gdbarch_deprecated_push_dummy_frame (gdbarch, hppa_push_dummy_frame);
- set_gdbarch_deprecated_pop_frame (gdbarch, hppa_pop_frame);
- set_gdbarch_deprecated_call_dummy_length (gdbarch, INSTRUCTION_SIZE * 28);
- /* set_gdbarch_deprecated_fix_call_dummy (gdbarch, hppa_fix_call_dummy); */
- set_gdbarch_deprecated_push_arguments (gdbarch, hppa_push_arguments);
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);
/* Helper for function argument information. */
set_gdbarch_fetch_pointer_argument (gdbarch, hppa_fetch_pointer_argument);
+ set_gdbarch_print_insn (gdbarch, print_insn_hppa);
+
+ /* 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. */
+ if (0)
+ {
+ }
+ else
+ {
+ switch (tdep->bytes_per_address)
+ {
+ case 4:
+ set_gdbarch_deprecated_call_dummy_length (gdbarch, hppa32_call_dummy_length);
+ set_gdbarch_deprecated_stack_align (gdbarch, hppa32_stack_align);
+ set_gdbarch_deprecated_reg_struct_has_addr (gdbarch, hppa_reg_struct_has_addr);
+ break;
+ case 8:
+ set_gdbarch_deprecated_call_dummy_breakpoint_offset (gdbarch, hppa64_call_dummy_breakpoint_offset);
+ set_gdbarch_deprecated_call_dummy_length (gdbarch, hppa64_call_dummy_length);
+ set_gdbarch_deprecated_stack_align (gdbarch, hppa64_stack_align);
+ break;
+ }
+ set_gdbarch_deprecated_push_dummy_frame (gdbarch, hppa_push_dummy_frame);
+ /* set_gdbarch_deprecated_fix_call_dummy (gdbarch, hppa_fix_call_dummy); */
+ set_gdbarch_deprecated_push_arguments (gdbarch, hppa_push_arguments);
+ }
+
+ /* Struct return methods. */
+ if (0)
+ {
+ }
+ else
+ {
+ switch (tdep->bytes_per_address)
+ {
+ case 4:
+ set_gdbarch_deprecated_extract_return_value (gdbarch, hppa32_extract_return_value);
+ set_gdbarch_use_struct_convention (gdbarch, hppa32_use_struct_convention);
+ set_gdbarch_deprecated_store_return_value (gdbarch, hppa32_store_return_value);
+ break;
+ case 8:
+ set_gdbarch_deprecated_extract_return_value (gdbarch, hppa64_extract_return_value);
+ set_gdbarch_use_struct_convention (gdbarch, hppa64_use_struct_convention);
+ set_gdbarch_deprecated_store_return_value (gdbarch, hppa64_store_return_value);
+ break;
+ }
+ set_gdbarch_deprecated_store_struct_return (gdbarch, hppa_store_struct_return);
+ }
+
+ /* Frame unwind methods. */
+ if (0)
+ {
+ set_gdbarch_unwind_dummy_id (gdbarch, hppa_unwind_dummy_id);
+ set_gdbarch_unwind_pc (gdbarch, hppa_unwind_pc);
+ frame_unwind_append_sniffer (gdbarch, hppa_frame_unwind_sniffer);
+ frame_base_append_sniffer (gdbarch, hppa_frame_base_sniffer);
+ }
+ else
+ {
+ set_gdbarch_deprecated_saved_pc_after_call (gdbarch, hppa_saved_pc_after_call);
+ set_gdbarch_deprecated_init_frame_pc (gdbarch, deprecated_init_frame_pc_default);
+ set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, hppa_frame_init_saved_regs);
+ set_gdbarch_deprecated_init_extra_frame_info (gdbarch, hppa_init_extra_frame_info);
+ set_gdbarch_deprecated_frame_chain (gdbarch, hppa_frame_chain);
+ set_gdbarch_deprecated_frame_chain_valid (gdbarch, hppa_frame_chain_valid);
+ set_gdbarch_deprecated_frameless_function_invocation (gdbarch, hppa_frameless_function_invocation);
+ set_gdbarch_deprecated_frame_saved_pc (gdbarch, hppa_frame_saved_pc);
+ set_gdbarch_deprecated_pop_frame (gdbarch, hppa_pop_frame);
+ }
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
return gdbarch;
}
void break_at_finish_at_depth_command (char *arg, int from_tty);
gdbarch_register (bfd_arch_hppa, hppa_gdbarch_init, hppa_dump_tdep);
- deprecated_tm_print_insn = print_insn_hppa;
add_cmd ("unwind", class_maintenance, unwind_command,
"Print unwind table entry at given address.",