/* Target-dependent code for the HP PA architecture, for GDB.
- Copyright 1986, 87, 89, 90, 91, 92, 93, 94, 95, 96, 1999
- Free Software Foundation, Inc.
+
+ Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+ 1996, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
#include "bfd.h"
#include "inferior.h"
#include "value.h"
+#include "regcache.h"
+#include "completer.h"
+#include "language.h"
+#include "osabi.h"
+#include "gdb_assert.h"
/* For argument passing to the inferior */
#include "symtab.h"
/*#include <sys/user.h> After a.out.h */
#include <sys/file.h>
#include "gdb_stat.h"
-#include "wait.h"
+#include "gdb_wait.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "symfile.h"
#include "objfiles.h"
-/* To support asking "What CPU is this?" */
-#include <unistd.h>
+/* Some local constants. */
+static const int hppa_num_regs = 128;
/* To support detection of the pseudo-initial frame
that threads have. */
#define THREAD_INITIAL_FRAME_SYMBOL "__pthread_exit"
#define THREAD_INITIAL_FRAME_SYM_LEN sizeof(THREAD_INITIAL_FRAME_SYMBOL)
-static int extract_5_load PARAMS ((unsigned int));
+static int extract_5_load (unsigned int);
-static unsigned extract_5R_store PARAMS ((unsigned int));
+static unsigned extract_5R_store (unsigned int);
-static unsigned extract_5r_store PARAMS ((unsigned int));
+static unsigned extract_5r_store (unsigned int);
-static void find_dummy_frame_regs PARAMS ((struct frame_info *,
- struct frame_saved_regs *));
+static void find_dummy_frame_regs (struct frame_info *,
+ struct frame_saved_regs *);
-static int find_proc_framesize PARAMS ((CORE_ADDR));
+static int find_proc_framesize (CORE_ADDR);
-static int find_return_regnum PARAMS ((CORE_ADDR));
+static int find_return_regnum (CORE_ADDR);
-struct unwind_table_entry *find_unwind_entry PARAMS ((CORE_ADDR));
+struct unwind_table_entry *find_unwind_entry (CORE_ADDR);
-static int extract_17 PARAMS ((unsigned int));
+static int extract_17 (unsigned int);
-static unsigned deposit_21 PARAMS ((unsigned int, unsigned int));
+static unsigned deposit_21 (unsigned int, unsigned int);
-static int extract_21 PARAMS ((unsigned));
+static int extract_21 (unsigned);
-static unsigned deposit_14 PARAMS ((int, unsigned int));
+static unsigned deposit_14 (int, unsigned int);
-static int extract_14 PARAMS ((unsigned));
+static int extract_14 (unsigned);
-static void unwind_command PARAMS ((char *, int));
+static void unwind_command (char *, int);
-static int low_sign_extend PARAMS ((unsigned int, unsigned int));
+static int low_sign_extend (unsigned int, unsigned int);
-static int sign_extend PARAMS ((unsigned int, unsigned int));
+static int sign_extend (unsigned int, unsigned int);
-static int restore_pc_queue PARAMS ((struct frame_saved_regs *));
+static int restore_pc_queue (struct frame_saved_regs *);
-static int hppa_alignof PARAMS ((struct type *));
+static int hppa_alignof (struct type *);
/* To support multi-threading and stepping. */
-int hppa_prepare_to_proceed PARAMS (());
-
-static int prologue_inst_adjust_sp PARAMS ((unsigned long));
-
-static int is_branch PARAMS ((unsigned long));
-
-static int inst_saves_gr PARAMS ((unsigned long));
-
-static int inst_saves_fr PARAMS ((unsigned long));
-
-static int pc_in_interrupt_handler PARAMS ((CORE_ADDR));
-
-static int pc_in_linker_stub PARAMS ((CORE_ADDR));
-
-static int compare_unwind_entries PARAMS ((const void *, const void *));
-
-static void read_unwind_info PARAMS ((struct objfile *));
-
-static void internalize_unwinds PARAMS ((struct objfile *,
- struct unwind_table_entry *,
- asection *, unsigned int,
- unsigned int, CORE_ADDR));
-static void pa_print_registers PARAMS ((char *, int, int));
-static void pa_strcat_registers PARAMS ((char *, int, int, GDB_FILE *));
-static void pa_register_look_aside PARAMS ((char *, int, long *));
-static void pa_print_fp_reg PARAMS ((int));
-static void pa_strcat_fp_reg PARAMS ((int, GDB_FILE *, enum precision_type));
+int hppa_prepare_to_proceed ();
+
+static int prologue_inst_adjust_sp (unsigned long);
+
+static int is_branch (unsigned long);
+
+static int inst_saves_gr (unsigned long);
+
+static int inst_saves_fr (unsigned long);
+
+static int pc_in_interrupt_handler (CORE_ADDR);
+
+static int pc_in_linker_stub (CORE_ADDR);
+
+static int compare_unwind_entries (const void *, const void *);
+
+static void read_unwind_info (struct objfile *);
+
+static void internalize_unwinds (struct objfile *,
+ struct unwind_table_entry *,
+ asection *, unsigned int,
+ unsigned int, CORE_ADDR);
+static void pa_print_registers (char *, int, int);
+static void pa_strcat_registers (char *, int, int, struct ui_file *);
+static void pa_register_look_aside (char *, int, long *);
+static void pa_print_fp_reg (int);
+static void pa_strcat_fp_reg (int, struct ui_file *, enum precision_type);
+static void record_text_segment_lowaddr (bfd *, asection *, void *);
+/* FIXME: brobecker 2002-11-07: We will likely be able to make the
+ following functions static, once we hppa is partially multiarched. */
+int hppa_reg_struct_has_addr (int gcc_p, struct type *type);
+CORE_ADDR hppa_skip_prologue (CORE_ADDR pc);
+CORE_ADDR hppa_skip_trampoline_code (CORE_ADDR pc);
+int hppa_in_solib_call_trampoline (CORE_ADDR pc, char *name);
+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);
+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);
+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);
+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_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe);
+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);
+CORE_ADDR hppa_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun,
+ int nargs, struct value **args,
+ struct type *type, int gcc_p);
+CORE_ADDR hppa_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr);
+CORE_ADDR hppa_smash_text_address (CORE_ADDR addr);
+CORE_ADDR hppa_target_read_pc (ptid_t ptid);
+void hppa_target_write_pc (CORE_ADDR v, ptid_t ptid);
+CORE_ADDR hppa_target_read_fp (void);
typedef struct
{
}
args_for_find_stub;
-static int cover_find_stub_with_shl_get (PTR);
+static int cover_find_stub_with_shl_get (void *);
static int is_pa_2 = 0; /* False */
/* In breakpoint.c */
extern int exception_catchpoints_are_fragile;
-/* This is defined in valops.c. */
-extern value_ptr
- find_function_in_inferior PARAMS ((char *));
-
/* Should call_function allocate stack space for a struct return? */
+
int
-hppa_use_struct_convention (gcc_p, type)
- int gcc_p;
- struct type *type;
+hppa_use_struct_convention (int gcc_p, struct type *type)
{
- return (TYPE_LENGTH (type) > 8);
+ return (TYPE_LENGTH (type) > 2 * REGISTER_SIZE);
}
\f
value. */
static int
-sign_extend (val, bits)
- unsigned val, bits;
+sign_extend (unsigned val, unsigned bits)
{
return (int) (val >> (bits - 1) ? (-1 << bits) | val : val);
}
/* For many immediate values the sign bit is the low bit! */
static int
-low_sign_extend (val, bits)
- unsigned val, bits;
+low_sign_extend (unsigned val, unsigned bits)
{
return (int) ((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
}
/* extract the immediate field from a ld{bhw}s instruction */
static int
-extract_5_load (word)
- unsigned word;
+extract_5_load (unsigned word)
{
return low_sign_extend (word >> 16 & MASK_5, 5);
}
/* extract the immediate field from a break instruction */
static unsigned
-extract_5r_store (word)
- unsigned word;
+extract_5r_store (unsigned word)
{
return (word & MASK_5);
}
/* extract the immediate field from a {sr}sm instruction */
static unsigned
-extract_5R_store (word)
- unsigned word;
+extract_5R_store (unsigned word)
{
return (word >> 16 & MASK_5);
}
/* extract a 14 bit immediate field */
static int
-extract_14 (word)
- unsigned word;
+extract_14 (unsigned word)
{
return low_sign_extend (word & MASK_14, 14);
}
/* deposit a 14 bit constant in a word */
static unsigned
-deposit_14 (opnd, word)
- int opnd;
- unsigned word;
+deposit_14 (int opnd, unsigned word)
{
unsigned sign = (opnd < 0 ? 1 : 0);
/* extract a 21 bit constant */
static int
-extract_21 (word)
- unsigned word;
+extract_21 (unsigned word)
{
int val;
the low 21 bits of opnd are relevant */
static unsigned
-deposit_21 (opnd, word)
- unsigned opnd, word;
+deposit_21 (unsigned opnd, unsigned word)
{
unsigned val = 0;
19 bit signed value. */
static int
-extract_17 (word)
- unsigned word;
+extract_17 (unsigned word)
{
return sign_extend (GET_FIELD (word, 19, 28) |
GET_FIELD (word, 29, 29) << 10 |
larger than the first, and zero if they are equal. */
static int
-compare_unwind_entries (arg1, arg2)
- const void *arg1;
- const void *arg2;
+compare_unwind_entries (const void *arg1, const void *arg2)
{
const struct unwind_table_entry *a = arg1;
const struct unwind_table_entry *b = arg2;
return 0;
}
+static CORE_ADDR low_text_segment_address;
+
+static void
+record_text_segment_lowaddr (bfd *abfd, asection *section, void *ignored)
+{
+ if (((section->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
+ == (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
+ && section->vma < low_text_segment_address)
+ low_text_segment_address = section->vma;
+}
+
static void
-internalize_unwinds (objfile, table, section, entries, size, text_offset)
- struct objfile *objfile;
- struct unwind_table_entry *table;
- asection *section;
- unsigned int entries, size;
- CORE_ADDR text_offset;
+internalize_unwinds (struct objfile *objfile, struct unwind_table_entry *table,
+ asection *section, unsigned int entries, unsigned int size,
+ CORE_ADDR text_offset)
{
/* We will read the unwind entries into temporary memory, then
fill in the actual unwind table. */
unsigned i;
char *buf = alloca (size);
+ low_text_segment_address = -1;
+
+ /* If addresses are 64 bits wide, 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 (TARGET_PTR_BIT == 64 && text_offset == 0)
+ {
+ bfd_map_over_sections (objfile->obfd,
+ record_text_segment_lowaddr, NULL);
+
+ /* ?!? Mask off some low bits. Should this instead subtract
+ out the lowest section's filepos or something like that?
+ This looks very hokey to me. */
+ low_text_segment_address &= ~0xfff;
+ text_offset += low_text_segment_address;
+ }
+
bfd_get_section_contents (objfile->obfd, section, buf, 0, size);
/* Now internalize the information being careful to handle host/target
gets freed when the objfile is destroyed. */
static void
-read_unwind_info (objfile)
- struct objfile *objfile;
+read_unwind_info (struct objfile *objfile)
{
- asection *unwind_sec, *elf_unwind_sec, *stub_unwind_sec;
- unsigned unwind_size, elf_unwind_size, stub_unwind_size, total_size;
- unsigned index, unwind_entries, elf_unwind_entries;
+ 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 obj_unwind_info *ui;
ui->cache = NULL;
ui->last = -1;
- /* Get hooks to all unwind sections. Note there is no linker-stub unwind
- section in ELF at the moment. */
- unwind_sec = bfd_get_section_by_name (objfile->obfd, "$UNWIND_START$");
- elf_unwind_sec = bfd_get_section_by_name (objfile->obfd, ".PARISC.unwind");
- stub_unwind_sec = bfd_get_section_by_name (objfile->obfd, "$UNWIND_END$");
-
- /* Get sizes and unwind counts for all sections. */
- if (unwind_sec)
+ /* 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)
{
- unwind_size = bfd_section_size (objfile->obfd, unwind_sec);
- unwind_entries = unwind_size / UNWIND_ENTRY_SIZE;
- }
- else
- {
- unwind_size = 0;
- unwind_entries = 0;
- }
+ 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;
- if (elf_unwind_sec)
- {
- elf_unwind_size = bfd_section_size (objfile->obfd, elf_unwind_sec); /* purecov: deadcode */
- elf_unwind_entries = elf_unwind_size / UNWIND_ENTRY_SIZE; /* purecov: deadcode */
- }
- else
- {
- elf_unwind_size = 0;
- elf_unwind_entries = 0;
+ total_entries += unwind_entries;
+ }
}
+ /* 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)
{
stub_unwind_size = bfd_section_size (objfile->obfd, stub_unwind_sec);
}
/* Compute total number of unwind entries and their total size. */
- total_entries = unwind_entries + elf_unwind_entries + stub_entries;
+ total_entries += stub_entries;
total_size = total_entries * sizeof (struct unwind_table_entry);
/* Allocate memory for the unwind table. */
obstack_alloc (&objfile->psymbol_obstack, total_size);
ui->last = total_entries - 1;
- /* Internalize the standard unwind entries. */
+ /* Now read in each unwind section and internalize the standard unwind
+ entries. */
index = 0;
- internalize_unwinds (objfile, &ui->table[index], unwind_sec,
- unwind_entries, unwind_size, text_offset);
- index += unwind_entries;
- internalize_unwinds (objfile, &ui->table[index], elf_unwind_sec,
- elf_unwind_entries, elf_unwind_size, text_offset);
- index += elf_unwind_entries;
-
- /* Now internalize the stub unwind entries. */
+ 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)
+ {
+ 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;
sizeof (obj_private_data_t));
obj_private->unwind_info = NULL;
obj_private->so_info = NULL;
+ obj_private->dp = 0;
- objfile->obj_private = (PTR) obj_private;
+ objfile->obj_private = obj_private;
}
obj_private = (obj_private_data_t *) objfile->obj_private;
obj_private->unwind_info = ui;
search of the unwind tables, we depend upon them to be sorted. */
struct unwind_table_entry *
-find_unwind_entry (pc)
- CORE_ADDR pc;
+find_unwind_entry (CORE_ADDR pc)
{
int first, middle, last;
struct objfile *objfile;
{
read_unwind_info (objfile);
if (objfile->obj_private == NULL)
- error ("Internal error reading unwind information."); /* purecov: deadcode */
+ error ("Internal error reading unwind information.");
ui = ((obj_private_data_t *) (objfile->obj_private))->unwind_info;
}
bizarre way in which someone (?) decided they wanted to handle
frame pointerless code in GDB. */
int
-hpread_adjust_stack_address (func_addr)
- CORE_ADDR func_addr;
+hpread_adjust_stack_address (CORE_ADDR func_addr)
{
struct unwind_table_entry *u;
kind. */
static int
-pc_in_interrupt_handler (pc)
- CORE_ADDR pc;
+pc_in_interrupt_handler (CORE_ADDR pc)
{
struct unwind_table_entry *u;
struct minimal_symbol *msym_us;
its frame isn't a pure interrupt frame. Deal with this. */
msym_us = lookup_minimal_symbol_by_pc (pc);
- return u->HP_UX_interrupt_marker && !IN_SIGTRAMP (pc, SYMBOL_NAME (msym_us));
+ return (u->HP_UX_interrupt_marker
+ && !PC_IN_SIGTRAMP (pc, DEPRECATED_SYMBOL_NAME (msym_us)));
}
/* Called when no unwind descriptor was found for PC. Returns 1 if it
- appears that PC is in a linker stub. */
+ appears that PC is in a linker stub.
+
+ ?!? Need to handle stubs which appear in PA64 code. */
static int
-pc_in_linker_stub (pc)
- CORE_ADDR pc;
+pc_in_linker_stub (CORE_ADDR pc)
{
int found_magic_instruction = 0;
int i;
}
static int
-find_return_regnum (pc)
- CORE_ADDR pc;
+find_return_regnum (CORE_ADDR pc)
{
struct unwind_table_entry *u;
/* Return size of frame, or -1 if we should use a frame pointer. */
static int
-find_proc_framesize (pc)
- CORE_ADDR pc;
+find_proc_framesize (CORE_ADDR pc)
{
struct unwind_table_entry *u;
struct minimal_symbol *msym_us;
/* If Save_SP is set, and we're not in an interrupt or signal caller,
then we have a frame pointer. Use it. */
- if (u->Save_SP && !pc_in_interrupt_handler (pc)
- && !IN_SIGTRAMP (pc, SYMBOL_NAME (msym_us)))
+ if (u->Save_SP
+ && !pc_in_interrupt_handler (pc)
+ && msym_us
+ && !PC_IN_SIGTRAMP (pc, DEPRECATED_SYMBOL_NAME (msym_us)))
return -1;
return u->Total_frame_size << 3;
}
/* Return offset from sp at which rp is saved, or 0 if not saved. */
-static int rp_saved PARAMS ((CORE_ADDR));
+static int rp_saved (CORE_ADDR);
static int
-rp_saved (pc)
- CORE_ADDR pc;
+rp_saved (CORE_ADDR pc)
{
struct unwind_table_entry *u;
}
if (u->Save_RP)
- return -20;
+ return (TARGET_PTR_BIT == 64 ? -16 : -20);
else if (u->stub_unwind.stub_type != 0)
{
switch (u->stub_unwind.stub_type)
}
\f
int
-frameless_function_invocation (frame)
- struct frame_info *frame;
+hppa_frameless_function_invocation (struct frame_info *frame)
{
struct unwind_table_entry *u;
return (u->Total_frame_size == 0 && u->stub_unwind.stub_type == 0);
}
+/* Immediately after a function call, return the saved pc.
+ Can't go through the frames for this because on some machines
+ the new frame is not set up until the new function executes
+ some instructions. */
+
CORE_ADDR
-saved_pc_after_call (frame)
- struct frame_info *frame;
+hppa_saved_pc_after_call (struct frame_info *frame)
{
int ret_regnum;
CORE_ADDR pc;
the stub will return to out of the stack. */
u = find_unwind_entry (pc);
if (u && u->stub_unwind.stub_type != 0)
- return FRAME_SAVED_PC (frame);
+ return DEPRECATED_FRAME_SAVED_PC (frame);
else
return pc;
}
\f
CORE_ADDR
-hppa_frame_saved_pc (frame)
- struct frame_info *frame;
+hppa_frame_saved_pc (struct frame_info *frame)
{
CORE_ADDR pc = get_frame_pc (frame);
struct unwind_table_entry *u;
are saved in the exact same order as GDB numbers registers. How
convienent. */
if (pc_in_interrupt_handler (pc))
- return read_memory_integer (frame->frame + PC_REGNUM * 4, 4) & ~0x3;
+ return read_memory_integer (frame->frame + PC_REGNUM * 4,
+ TARGET_PTR_BIT / 8) & ~0x3;
+
+ if ((frame->pc >= frame->frame
+ && frame->pc <= (frame->frame
+ /* A call dummy is sized in words, but it is
+ actually a series of instructions. Account
+ for that scaling factor. */
+ + ((REGISTER_SIZE / INSTRUCTION_SIZE)
+ * CALL_DUMMY_LENGTH)
+ /* Similarly we have to account for 64bit
+ wide register saves. */
+ + (32 * REGISTER_SIZE)
+ /* We always consider FP regs 8 bytes long. */
+ + (NUM_REGS - FP0_REGNUM) * 8
+ /* Similarly we have to account for 64bit
+ wide register saves. */
+ + (6 * REGISTER_SIZE))))
+ {
+ return read_memory_integer ((frame->frame
+ + (TARGET_PTR_BIT == 64 ? -16 : -20)),
+ TARGET_PTR_BIT / 8) & ~0x3;
+ }
#ifdef FRAME_SAVED_PC_IN_SIGTRAMP
/* Deal with signal handler caller frames too. */
- if (frame->signal_handler_caller)
+ if ((get_frame_type (frame) == SIGTRAMP_FRAME))
{
CORE_ADDR rp;
FRAME_SAVED_PC_IN_SIGTRAMP (frame, &rp);
}
#endif
- if (frameless_function_invocation (frame))
+ if (hppa_frameless_function_invocation (frame))
{
int ret_regnum;
register area to get the return pointer (the values
in the registers may not correspond to anything useful). */
if (frame->next
- && (frame->next->signal_handler_caller
+ && ((get_frame_type (frame->next) == SIGTRAMP_FRAME)
|| pc_in_interrupt_handler (frame->next->pc)))
{
struct frame_saved_regs saved_regs;
- get_frame_saved_regs (frame->next, &saved_regs);
- if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4) & 0x2)
+ deprecated_get_frame_saved_regs (frame->next, &saved_regs);
+ if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
+ TARGET_PTR_BIT / 8) & 0x2)
{
- pc = read_memory_integer (saved_regs.regs[31], 4) & ~0x3;
+ pc = read_memory_integer (saved_regs.regs[31],
+ TARGET_PTR_BIT / 8) & ~0x3;
/* Syscalls are really two frames. The syscall stub itself
with a return pointer in %rp and the kernel call with
a return pointer in %r31. We return the %rp variant
if %r31 is the same as frame->pc. */
if (pc == frame->pc)
- pc = read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~0x3;
+ pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
+ TARGET_PTR_BIT / 8) & ~0x3;
}
else
- pc = read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~0x3;
+ pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
+ TARGET_PTR_BIT / 8) & ~0x3;
}
else
pc = read_register (ret_regnum) & ~0x3;
information out of the saved register info. */
if (rp_offset == 0
&& frame->next
- && (frame->next->signal_handler_caller
+ && ((get_frame_type (frame->next) == SIGTRAMP_FRAME)
|| pc_in_interrupt_handler (frame->next->pc)))
{
struct frame_saved_regs saved_regs;
- get_frame_saved_regs (frame->next, &saved_regs);
- if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4) & 0x2)
+ deprecated_get_frame_saved_regs (frame->next, &saved_regs);
+ if (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
+ TARGET_PTR_BIT / 8) & 0x2)
{
- pc = read_memory_integer (saved_regs.regs[31], 4) & ~0x3;
+ pc = read_memory_integer (saved_regs.regs[31],
+ TARGET_PTR_BIT / 8) & ~0x3;
/* Syscalls are really two frames. The syscall stub itself
with a return pointer in %rp and the kernel call with
a return pointer in %r31. We return the %rp variant
if %r31 is the same as frame->pc. */
if (pc == frame->pc)
- pc = read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~0x3;
+ pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
+ TARGET_PTR_BIT / 8) & ~0x3;
}
else
- pc = read_memory_integer (saved_regs.regs[RP_REGNUM], 4) & ~0x3;
+ pc = read_memory_integer (saved_regs.regs[RP_REGNUM],
+ TARGET_PTR_BIT / 8) & ~0x3;
}
else if (rp_offset == 0)
{
else
{
old_pc = pc;
- pc = read_memory_integer (frame->frame + rp_offset, 4) & ~0x3;
+ pc = read_memory_integer (frame->frame + rp_offset,
+ TARGET_PTR_BIT / 8) & ~0x3;
}
}
in a system call. */
void
-init_extra_frame_info (fromleaf, frame)
- int fromleaf;
- struct frame_info *frame;
+hppa_init_extra_frame_info (int fromleaf, struct frame_info *frame)
{
int flags;
int framesize;
if (frame->next && !fromleaf)
return;
- /* If the next frame represents a frameless function invocation
- then we have to do some adjustments that are normally done by
- FRAME_CHAIN. (FRAME_CHAIN is not called in this case.) */
+ /* If the next frame represents a frameless function invocation then
+ we have to do some adjustments that are normally done by
+ DEPRECATED_FRAME_CHAIN. (DEPRECATED_FRAME_CHAIN is not called in
+ this case.) */
if (fromleaf)
{
/* Find the framesize of *this* frame without peeking at the PC
in the current frame structure (it isn't set yet). */
- framesize = find_proc_framesize (FRAME_SAVED_PC (get_next_frame (frame)));
+ framesize = find_proc_framesize (DEPRECATED_FRAME_SAVED_PC (get_next_frame (frame)));
/* Now adjust our base frame accordingly. If we have a frame pointer
use it, else subtract the size of this frame from the current
frame->frame = read_register (SP_REGNUM) - framesize;
}
\f
-/* Given a GDB frame, determine the address of the calling function's frame.
- This will be used to create a new GDB frame struct, and then
- INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame.
+/* Given a GDB frame, determine the address of the calling function's
+ frame. This will be used to create a new GDB frame struct, and
+ then DEPRECATED_INIT_EXTRA_FRAME_INFO and DEPRECATED_INIT_FRAME_PC
+ will be called for the new frame.
This may involve searching through prologues for several functions
at boundaries where GCC calls HP C code, or where code which has
a frame pointer calls code without a frame pointer. */
CORE_ADDR
-frame_chain (frame)
- struct frame_info *frame;
+hppa_frame_chain (struct frame_info *frame)
{
int my_framesize, caller_framesize;
struct unwind_table_entry *u;
CORE_ADDR frame_base;
struct frame_info *tmp_frame;
+ /* A frame in the current frame list, or zero. */
+ struct frame_info *saved_regs_frame = 0;
+ /* Where the registers were saved in saved_regs_frame.
+ If saved_regs_frame is zero, this is garbage. */
+ struct frame_saved_regs saved_regs;
+
CORE_ADDR caller_pc;
struct minimal_symbol *min_frame_symbol;
pthread library itself, you'd get errors.
So for today, we don't make that check. */
- frame_symbol_name = SYMBOL_NAME (min_frame_symbol);
+ frame_symbol_name = DEPRECATED_SYMBOL_NAME (min_frame_symbol);
if (frame_symbol_name != 0)
{
if (0 == strncmp (frame_symbol_name,
pull the old stack pointer from. Also see frame_saved_pc for
code to dig a saved PC out of the save state structure. */
if (pc_in_interrupt_handler (frame->pc))
- frame_base = read_memory_integer (frame->frame + SP_REGNUM * 4, 4);
+ frame_base = read_memory_integer (frame->frame + SP_REGNUM * 4,
+ TARGET_PTR_BIT / 8);
#ifdef FRAME_BASE_BEFORE_SIGTRAMP
- else if (frame->signal_handler_caller)
+ else if ((get_frame_type (frame) == SIGTRAMP_FRAME))
{
FRAME_BASE_BEFORE_SIGTRAMP (frame, &frame_base);
}
/* Get frame sizes for the current frame and the frame of the
caller. */
my_framesize = find_proc_framesize (frame->pc);
- caller_pc = FRAME_SAVED_PC (frame);
+ caller_pc = DEPRECATED_FRAME_SAVED_PC (frame);
/* If we can't determine the caller's PC, then it's not likely we can
really determine anything meaningful about its frame. We'll consider
if (caller_pc == (CORE_ADDR) 0)
return (CORE_ADDR) 0;
- caller_framesize = find_proc_framesize (FRAME_SAVED_PC (frame));
+ caller_framesize = find_proc_framesize (DEPRECATED_FRAME_SAVED_PC (frame));
/* If caller does not have a frame pointer, then its frame
can be found at current_frame - caller_framesize. */
The previous frame pointer is found at the top of the current frame. */
if (caller_framesize == -1 && my_framesize == -1)
{
- return read_memory_integer (frame_base, 4);
+ return read_memory_integer (frame_base, TARGET_PTR_BIT / 8);
}
/* Caller has a frame pointer, but callee does not. This is a little
more difficult as GCC and HP C lay out locals and callee register save
We use information from unwind descriptors to determine if %r3
is saved into the stack (Entry_GR field has this information). */
- tmp_frame = frame;
- while (tmp_frame)
+ for (tmp_frame = frame; tmp_frame; tmp_frame = tmp_frame->next)
{
u = find_unwind_entry (tmp_frame->pc);
return (CORE_ADDR) 0;
}
- /* Entry_GR specifies the number of callee-saved general registers
- saved in the stack. It starts at %r3, so %r3 would be 1. */
- if (u->Entry_GR >= 1 || u->Save_SP
- || tmp_frame->signal_handler_caller
+ if (u->Save_SP
+ || (get_frame_type (tmp_frame) == SIGTRAMP_FRAME)
|| pc_in_interrupt_handler (tmp_frame->pc))
break;
- else
- tmp_frame = tmp_frame->next;
+
+ /* Entry_GR specifies the number of callee-saved general registers
+ saved in the stack. It starts at %r3, so %r3 would be 1. */
+ if (u->Entry_GR >= 1)
+ {
+ /* The unwind entry claims that r3 is saved here. However,
+ in optimized code, GCC often doesn't actually save r3.
+ We'll discover this if we look at the prologue. */
+ deprecated_get_frame_saved_regs (tmp_frame, &saved_regs);
+ saved_regs_frame = tmp_frame;
+
+ /* If we have an address for r3, that's good. */
+ if (saved_regs.regs[FP_REGNUM])
+ break;
+ }
}
if (tmp_frame)
/* We may have walked down the chain into a function with a frame
pointer. */
if (u->Save_SP
- && !tmp_frame->signal_handler_caller
+ && !(get_frame_type (tmp_frame) == SIGTRAMP_FRAME)
&& !pc_in_interrupt_handler (tmp_frame->pc))
{
- return read_memory_integer (tmp_frame->frame, 4);
+ return read_memory_integer (tmp_frame->frame, TARGET_PTR_BIT / 8);
}
/* %r3 was saved somewhere in the stack. Dig it out. */
else
{
- struct frame_saved_regs saved_regs;
-
/* Sick.
For optimization purposes many kernels don't have the
fail miserably if the function which performs the
system call has a variable sized stack frame. */
- get_frame_saved_regs (tmp_frame, &saved_regs);
+ if (tmp_frame != saved_regs_frame)
+ deprecated_get_frame_saved_regs (tmp_frame, &saved_regs);
/* Abominable hack. */
if (current_target.to_has_execution == 0
&& ((saved_regs.regs[FLAGS_REGNUM]
- && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4)
+ && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
+ TARGET_PTR_BIT / 8)
& 0x2))
|| (saved_regs.regs[FLAGS_REGNUM] == 0
&& read_register (FLAGS_REGNUM) & 0x2)))
{
- u = find_unwind_entry (FRAME_SAVED_PC (frame));
+ u = find_unwind_entry (DEPRECATED_FRAME_SAVED_PC (frame));
if (!u)
{
- return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+ return read_memory_integer (saved_regs.regs[FP_REGNUM],
+ TARGET_PTR_BIT / 8);
}
else
{
}
}
- return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+ return read_memory_integer (saved_regs.regs[FP_REGNUM],
+ TARGET_PTR_BIT / 8);
}
}
else
{
- struct frame_saved_regs saved_regs;
-
/* Get the innermost frame. */
tmp_frame = frame;
while (tmp_frame->next != NULL)
tmp_frame = tmp_frame->next;
- get_frame_saved_regs (tmp_frame, &saved_regs);
+ if (tmp_frame != saved_regs_frame)
+ deprecated_get_frame_saved_regs (tmp_frame, &saved_regs);
+
/* Abominable hack. See above. */
if (current_target.to_has_execution == 0
&& ((saved_regs.regs[FLAGS_REGNUM]
- && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM], 4)
+ && (read_memory_integer (saved_regs.regs[FLAGS_REGNUM],
+ TARGET_PTR_BIT / 8)
& 0x2))
|| (saved_regs.regs[FLAGS_REGNUM] == 0
&& read_register (FLAGS_REGNUM) & 0x2)))
{
- u = find_unwind_entry (FRAME_SAVED_PC (frame));
+ u = find_unwind_entry (DEPRECATED_FRAME_SAVED_PC (frame));
if (!u)
{
- return read_memory_integer (saved_regs.regs[FP_REGNUM], 4);
+ return read_memory_integer (saved_regs.regs[FP_REGNUM],
+ TARGET_PTR_BIT / 8);
}
else
{
was compiled with gcc. */
int
-hppa_frame_chain_valid (chain, thisframe)
- CORE_ADDR chain;
- struct frame_info *thisframe;
+hppa_frame_chain_valid (CORE_ADDR chain, struct frame_info *thisframe)
{
struct minimal_symbol *msym_us;
struct minimal_symbol *msym_start;
struct unwind_table_entry *u, *next_u = NULL;
struct frame_info *next;
- if (!chain)
- return 0;
-
u = find_unwind_entry (thisframe->pc);
if (u == NULL)
indistinguishable (as nearly as I can tell) from the symbol for a function
which is (legitimately, since it is in the user's namespace)
named Ltext_end, so we can't just ignore it. */
- msym_us = lookup_minimal_symbol_by_pc (FRAME_SAVED_PC (thisframe));
+ msym_us = lookup_minimal_symbol_by_pc (DEPRECATED_FRAME_SAVED_PC (thisframe));
msym_start = lookup_minimal_symbol ("_start", NULL, NULL);
if (msym_us
&& msym_start
and doesn't "call" an interrupt routine or signal handler caller,
then its not valid. */
if (u->Save_SP || u->Total_frame_size || u->stub_unwind.stub_type != 0
- || (thisframe->next && thisframe->next->signal_handler_caller)
+ || (thisframe->next && (get_frame_type (thisframe->next) == SIGTRAMP_FRAME))
|| (next_u && next_u->HP_UX_interrupt_marker))
return 1;
return 0;
}
-/*
- These functions deal with saving and restoring register state
- around a function call in the inferior. They keep the stack
- double-word aligned; eventually, on an hp700, the stack will have
- to be aligned to a 64-byte boundary. */
+/* These functions deal with saving and restoring register state
+ around a function call in the inferior. They keep the stack
+ double-word aligned; eventually, on an hp700, the stack will have
+ to be aligned to a 64-byte boundary. */
void
-push_dummy_frame (inf_status)
- struct inferior_status *inf_status;
+hppa_push_dummy_frame (void)
{
CORE_ADDR sp, pc, pcspace;
register int regnum;
- int int_buffer;
+ CORE_ADDR int_buffer;
double freg_buffer;
- /* Oh, what a hack. If we're trying to perform an inferior call
- while the inferior is asleep, we have to make sure to clear
- the "in system call" bit in the flag register (the call will
- start after the syscall returns, so we're no longer in the system
- call!) This state is kept in "inf_status", change it there.
-
- We also need a number of horrid hacks to deal with lossage in the
- PC queue registers (apparently they're not valid when the in syscall
- bit is set). */
- pc = target_read_pc (inferior_pid);
+ pc = hppa_target_read_pc (inferior_ptid);
int_buffer = read_register (FLAGS_REGNUM);
if (int_buffer & 0x2)
{
- unsigned int sid;
- int_buffer &= ~0x2;
- write_inferior_status_register (inf_status, 0, int_buffer);
- write_inferior_status_register (inf_status, PCOQ_HEAD_REGNUM, pc + 0);
- write_inferior_status_register (inf_status, PCOQ_TAIL_REGNUM, pc + 4);
- sid = (pc >> 30) & 0x3;
+ const unsigned int sid = (pc >> 30) & 0x3;
if (sid == 0)
pcspace = read_register (SR4_REGNUM);
else
pcspace = read_register (SR4_REGNUM + 4 + sid);
- write_inferior_status_register (inf_status, PCSQ_HEAD_REGNUM, pcspace);
- write_inferior_status_register (inf_status, PCSQ_TAIL_REGNUM, pcspace);
}
else
pcspace = read_register (PCSQ_HEAD_REGNUM);
/* Space for "arguments"; the RP goes in here. */
sp = read_register (SP_REGNUM) + 48;
int_buffer = read_register (RP_REGNUM) | 0x3;
- write_memory (sp - 20, (char *) &int_buffer, 4);
+
+ /* The 32bit and 64bit ABIs save the return pointer into different
+ stack slots. */
+ if (REGISTER_SIZE == 8)
+ write_memory (sp - 16, (char *) &int_buffer, REGISTER_SIZE);
+ else
+ write_memory (sp - 20, (char *) &int_buffer, REGISTER_SIZE);
int_buffer = TARGET_READ_FP ();
- write_memory (sp, (char *) &int_buffer, 4);
+ write_memory (sp, (char *) &int_buffer, REGISTER_SIZE);
write_register (FP_REGNUM, sp);
- sp += 8;
+ sp += 2 * REGISTER_SIZE;
for (regnum = 1; regnum < 32; regnum++)
if (regnum != RP_REGNUM && regnum != FP_REGNUM)
sp = push_word (sp, read_register (regnum));
- sp += 4;
+ /* This is not necessary for the 64bit ABI. In fact it is dangerous. */
+ if (REGISTER_SIZE != 8)
+ sp += 4;
for (regnum = FP0_REGNUM; regnum < NUM_REGS; regnum++)
{
- read_register_bytes (REGISTER_BYTE (regnum), (char *) &freg_buffer, 8);
+ deprecated_read_register_bytes (REGISTER_BYTE (regnum),
+ (char *) &freg_buffer, 8);
sp = push_bytes (sp, (char *) &freg_buffer, 8);
}
sp = push_word (sp, read_register (IPSW_REGNUM));
}
static void
-find_dummy_frame_regs (frame, frame_saved_regs)
- struct frame_info *frame;
- struct frame_saved_regs *frame_saved_regs;
+find_dummy_frame_regs (struct frame_info *frame,
+ struct frame_saved_regs *frame_saved_regs)
{
CORE_ADDR fp = frame->frame;
int i;
- frame_saved_regs->regs[RP_REGNUM] = (fp - 20) & ~0x3;
+ /* The 32bit and 64bit ABIs save RP into different locations. */
+ if (REGISTER_SIZE == 8)
+ frame_saved_regs->regs[RP_REGNUM] = (fp - 16) & ~0x3;
+ else
+ frame_saved_regs->regs[RP_REGNUM] = (fp - 20) & ~0x3;
+
frame_saved_regs->regs[FP_REGNUM] = fp;
- frame_saved_regs->regs[1] = fp + 8;
- for (fp += 12, i = 3; i < 32; i++)
+ frame_saved_regs->regs[1] = fp + (2 * REGISTER_SIZE);
+
+ for (fp += 3 * REGISTER_SIZE, i = 3; i < 32; i++)
{
if (i != FP_REGNUM)
{
frame_saved_regs->regs[i] = fp;
- fp += 4;
+ fp += REGISTER_SIZE;
}
}
- fp += 4;
+ /* This is not necessary or desirable for the 64bit ABI. */
+ if (REGISTER_SIZE != 8)
+ fp += 4;
+
for (i = FP0_REGNUM; i < NUM_REGS; i++, fp += 8)
frame_saved_regs->regs[i] = fp;
frame_saved_regs->regs[IPSW_REGNUM] = fp;
- frame_saved_regs->regs[SAR_REGNUM] = fp + 4;
- frame_saved_regs->regs[PCOQ_HEAD_REGNUM] = fp + 8;
- frame_saved_regs->regs[PCSQ_HEAD_REGNUM] = fp + 12;
- frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp + 16;
- frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp + 20;
+ frame_saved_regs->regs[SAR_REGNUM] = fp + REGISTER_SIZE;
+ frame_saved_regs->regs[PCOQ_HEAD_REGNUM] = fp + 2 * REGISTER_SIZE;
+ frame_saved_regs->regs[PCSQ_HEAD_REGNUM] = fp + 3 * REGISTER_SIZE;
+ frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp + 4 * REGISTER_SIZE;
+ frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp + 5 * REGISTER_SIZE;
}
void
-hppa_pop_frame ()
+hppa_pop_frame (void)
{
register struct frame_info *frame = get_current_frame ();
register CORE_ADDR fp, npc, target_pc;
struct frame_saved_regs fsr;
double freg_buffer;
- fp = FRAME_FP (frame);
- get_frame_saved_regs (frame, &fsr);
+ fp = get_frame_base (frame);
+ deprecated_get_frame_saved_regs (frame, &fsr);
#ifndef NO_PC_SPACE_QUEUE_RESTORE
if (fsr.regs[IPSW_REGNUM]) /* Restoring a call dummy frame */
for (regnum = 31; regnum > 0; regnum--)
if (fsr.regs[regnum])
- write_register (regnum, read_memory_integer (fsr.regs[regnum], 4));
+ write_register (regnum, read_memory_integer (fsr.regs[regnum],
+ REGISTER_SIZE));
for (regnum = NUM_REGS - 1; regnum >= FP0_REGNUM; regnum--)
if (fsr.regs[regnum])
{
read_memory (fsr.regs[regnum], (char *) &freg_buffer, 8);
- write_register_bytes (REGISTER_BYTE (regnum), (char *) &freg_buffer, 8);
+ deprecated_write_register_bytes (REGISTER_BYTE (regnum),
+ (char *) &freg_buffer, 8);
}
if (fsr.regs[IPSW_REGNUM])
write_register (IPSW_REGNUM,
- read_memory_integer (fsr.regs[IPSW_REGNUM], 4));
+ read_memory_integer (fsr.regs[IPSW_REGNUM],
+ REGISTER_SIZE));
if (fsr.regs[SAR_REGNUM])
write_register (SAR_REGNUM,
- read_memory_integer (fsr.regs[SAR_REGNUM], 4));
+ read_memory_integer (fsr.regs[SAR_REGNUM],
+ REGISTER_SIZE));
/* If the PC was explicitly saved, then just restore it. */
if (fsr.regs[PCOQ_TAIL_REGNUM])
{
- npc = read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM], 4);
+ npc = read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM],
+ REGISTER_SIZE);
write_register (PCOQ_TAIL_REGNUM, npc);
}
/* Else use the value in %rp to set the new PC. */
write_pc (npc);
}
- write_register (FP_REGNUM, read_memory_integer (fp, 4));
+ write_register (FP_REGNUM, read_memory_integer (fp, REGISTER_SIZE));
if (fsr.regs[IPSW_REGNUM]) /* call dummy */
write_register (SP_REGNUM, fp - 48);
for "return_command" will print the frame we returned to. */
sal = find_pc_line (target_pc, 0);
sal.pc = target_pc;
- breakpoint = set_momentary_breakpoint (sal, NULL, bp_finish);
+ breakpoint = set_momentary_breakpoint (sal, null_frame_id, bp_finish);
breakpoint->silent = 1;
/* So we can clean things up. */
- old_chain = make_cleanup ((make_cleanup_func) delete_breakpoint, breakpoint);
+ old_chain = make_cleanup_delete_breakpoint (breakpoint);
/* Start up the inferior. */
clear_proceed_status ();
proceed_to_finish = 1;
- proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_DEFAULT, 0);
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
/* Perform our cleanups. */
do_cleanups (old_chain);
queue space registers. */
static int
-restore_pc_queue (fsr)
- struct frame_saved_regs *fsr;
+restore_pc_queue (struct frame_saved_regs *fsr)
{
CORE_ADDR pc = read_pc ();
- CORE_ADDR new_pc = read_memory_integer (fsr->regs[PCOQ_HEAD_REGNUM], 4);
+ CORE_ADDR new_pc = read_memory_integer (fsr->regs[PCOQ_HEAD_REGNUM],
+ TARGET_PTR_BIT / 8);
struct target_waitstatus w;
int insn_count;
So, load up the registers and single step until we are in the
right place. */
- write_register (21, read_memory_integer (fsr->regs[PCSQ_HEAD_REGNUM], 4));
+ write_register (21, read_memory_integer (fsr->regs[PCSQ_HEAD_REGNUM],
+ REGISTER_SIZE));
write_register (22, new_pc);
for (insn_count = 0; insn_count < 3; insn_count++)
any other choice? Is there *any* way to do this stuff with
ptrace() or some equivalent?). */
resume (1, 0);
- target_wait (inferior_pid, &w);
+ target_wait (inferior_ptid, &w);
if (w.kind == TARGET_WAITKIND_SIGNALLED)
{
return 1;
}
-#if 0
+
+#ifdef PA20W_CALLING_CONVENTIONS
+
+/* 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. The call dummy code will copy
+ arguments into registers as needed by the ABI.
+
+ This ABI also requires that the caller provide an argument pointer
+ to the callee, so we do that too. */
+
CORE_ADDR
-hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
- int nargs;
- value_ptr *args;
- CORE_ADDR sp;
- int struct_return;
- CORE_ADDR struct_addr;
+hppa_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
{
/* array of arguments' offsets */
int *offset = (int *) alloca (nargs * sizeof (int));
- int cum = 0;
- int i, alignment;
+ /* array of arguments' lengths: real lengths in bytes, not aligned to
+ word size */
+ int *lengths = (int *) alloca (nargs * sizeof (int));
+
+ /* The value of SP as it was passed into this function after
+ aligning. */
+ CORE_ADDR orig_sp = STACK_ALIGN (sp);
+
+ /* The number of stack bytes occupied by the current argument. */
+ int bytes_reserved;
+
+ /* The total number of bytes reserved for the arguments. */
+ int cum_bytes_reserved = 0;
+
+ /* Similarly, but aligned. */
+ int cum_bytes_aligned = 0;
+ int i;
+
+ /* Iterate over each argument provided by the user. */
for (i = 0; i < nargs; i++)
{
- int x = 0;
- /* cum is the sum of the lengths in bytes of
- the arguments seen so far */
- cum += TYPE_LENGTH (VALUE_TYPE (args[i]));
+ struct type *arg_type = VALUE_TYPE (args[i]);
+
+ /* Integral scalar values smaller than a register are padded on
+ the left. We do this by promoting them to full-width,
+ although the ABI says to pad them with garbage. */
+ if (is_integral_type (arg_type)
+ && TYPE_LENGTH (arg_type) < REGISTER_SIZE)
+ {
+ args[i] = value_cast ((TYPE_UNSIGNED (arg_type)
+ ? builtin_type_unsigned_long
+ : builtin_type_long),
+ args[i]);
+ arg_type = VALUE_TYPE (args[i]);
+ }
+
+ lengths[i] = TYPE_LENGTH (arg_type);
- /* value must go at proper alignment. Assume alignment is a
- power of two. */
- alignment = hppa_alignof (VALUE_TYPE (args[i]));
+ /* Align the size of the argument to the word size for this
+ target. */
+ bytes_reserved = (lengths[i] + REGISTER_SIZE - 1) & -REGISTER_SIZE;
- if (cum % alignment)
- cum = (cum + alignment) & -alignment;
- offset[i] = -cum;
+ offset[i] = cum_bytes_reserved;
+ /* Aggregates larger than eight bytes (the only types larger
+ than eight bytes we have) are aligned on a 16-byte boundary,
+ possibly padded on the right with garbage. This may leave an
+ empty word on the stack, and thus an unused register, as per
+ the ABI. */
+ if (bytes_reserved > 8)
+ {
+ /* Round up the offset to a multiple of two slots. */
+ int new_offset = ((offset[i] + 2*REGISTER_SIZE-1)
+ & -(2*REGISTER_SIZE));
+
+ /* Note the space we've wasted, if any. */
+ bytes_reserved += new_offset - offset[i];
+ offset[i] = new_offset;
+ }
+
+ cum_bytes_reserved += bytes_reserved;
}
- sp += max ((cum + 7) & -8, 16);
+ /* CUM_BYTES_RESERVED already accounts for all the arguments
+ passed by the user. However, the ABIs mandate minimum stack space
+ allocations for outgoing arguments.
+
+ The ABIs also mandate minimum stack alignments which we must
+ preserve. */
+ cum_bytes_aligned = 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. */
for (i = 0; i < nargs; i++)
- write_memory (sp + offset[i], VALUE_CONTENTS (args[i]),
- TYPE_LENGTH (VALUE_TYPE (args[i])));
+ write_memory (orig_sp + offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
+ /* If a structure has to be returned, set up register 28 to hold its
+ address */
if (struct_return)
write_register (28, struct_addr);
- return sp + 32;
+
+ /* For the PA64 we must pass a pointer to the outgoing argument list.
+ The ABI mandates that the pointer should point to the first byte of
+ storage beyond the register flushback area.
+
+ However, the call dummy expects the outgoing argument pointer to
+ be passed in register %r4. */
+ write_register (4, orig_sp + REG_PARM_STACK_SPACE);
+
+ /* ?!? This needs further work. We need to set up the global data
+ pointer for this procedure. This assumes the same global pointer
+ for every procedure. The call dummy expects the dp value to
+ be passed in register %r6. */
+ write_register (6, read_register (27));
+
+ /* The stack will have 64 bytes of additional space for a frame marker. */
+ return sp + 64;
}
-#endif
-/* elz: I am rewriting this function, because the one above is a very
- obscure piece of code.
- This function pushes the arguments on the stack. The stack grows up
- on the PA.
- Each argument goes in one (or more) word (4 bytes) on the stack.
- The first four words for the args must be allocated, even if they
- are not used.
- The 'topmost' arg is arg0, the 'bottom-most' is arg3. (if you think of
- them as 1 word long).
- Below these there can be any number of arguments, as needed by the function.
- If an arg is bigger than one word, it will be written on the stack
- occupying as many words as needed. Args that are bigger than 64bits
- are not copied on the stack, a pointer is passed instead.
-
- On top of the arg0 word there are other 8 words (32bytes) which are used
- for other purposes */
+#else
+
+/* 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. The call dummy code will copy
+ arguments into registers as needed by the ABI. */
+
CORE_ADDR
-hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
- int nargs;
- value_ptr *args;
- CORE_ADDR sp;
- int struct_return;
- CORE_ADDR struct_addr;
+hppa_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
{
/* array of arguments' offsets */
int *offset = (int *) alloca (nargs * sizeof (int));
- /* array of arguments' lengths: real lengths in bytes, not aligned to word size */
+
+ /* array of arguments' lengths: real lengths in bytes, not aligned to
+ word size */
int *lengths = (int *) alloca (nargs * sizeof (int));
- int bytes_reserved; /* this is the number of bytes on the stack occupied by an
- argument. This will be always a multiple of 4 */
+ /* The number of stack bytes occupied by the current argument. */
+ int bytes_reserved;
- int cum_bytes_reserved = 0; /* this is the total number of bytes reserved by the args
- seen so far. It is a multiple of 4 always */
- int cum_bytes_aligned = 0; /* same as above, but aligned on 8 bytes */
- int i;
+ /* The total number of bytes reserved for the arguments. */
+ int cum_bytes_reserved = 0;
- /* When an arg does not occupy a whole word, for instance in bitfields:
- if the arg is x bits (0<x<32), it must be written
- starting from the (x-1)-th position down until the 0-th position.
- It is enough to align it to the word. */
- /* if an arg occupies 8 bytes, it must be aligned on the 64-bits
- high order word in odd arg word. */
- /* if an arg is larger than 64 bits, we need to pass a pointer to it, and
- copy the actual value on the stack, so that the callee can play with it.
- This is taken care of in valops.c in the call_function_by_hand function.
- The argument that is received in this function here has already be converted
- to a pointer to whatever is needed, so that it just can be pushed
- as a word argument */
+ /* Similarly, but aligned. */
+ int cum_bytes_aligned = 0;
+ int i;
+ /* Iterate over each argument provided by the user. */
for (i = 0; i < nargs; i++)
{
-
lengths[i] = TYPE_LENGTH (VALUE_TYPE (args[i]));
- if (lengths[i] % 4)
- bytes_reserved = (lengths[i] / 4) * 4 + 4;
- else
- bytes_reserved = lengths[i];
+ /* Align the size of the argument to the word size for this
+ target. */
+ bytes_reserved = (lengths[i] + REGISTER_SIZE - 1) & -REGISTER_SIZE;
- offset[i] = cum_bytes_reserved + lengths[i];
+ offset[i] = (cum_bytes_reserved
+ + (lengths[i] > 4 ? bytes_reserved : lengths[i]));
- if ((bytes_reserved == 8) && (offset[i] % 8)) /* if 64-bit arg is not 64 bit aligned */
+ /* If the argument is a double word argument, then it needs to be
+ double word aligned. */
+ if ((bytes_reserved == 2 * REGISTER_SIZE)
+ && (offset[i] % 2 * REGISTER_SIZE))
{
int new_offset = 0;
- /* bytes_reserved is already aligned to the word, so we put it at one word
- more down the stack. This will leave one empty word on the
- stack, and one unused register. This is OK, see the calling
- convention doc */
- /* the offset may have to be moved to the corresponding position
- one word down the stack, to maintain
- alignment. */
- new_offset = (offset[i] / 8) * 8 + 8;
- if ((new_offset - offset[i]) >= 4)
+ /* BYTES_RESERVED is already aligned to the word, so we put
+ the argument at one word more down the stack.
+
+ This will leave one empty word on the stack, and one unused
+ register as mandated by the ABI. */
+ new_offset = ((offset[i] + 2 * REGISTER_SIZE - 1)
+ & -(2 * REGISTER_SIZE));
+
+ if ((new_offset - offset[i]) >= 2 * REGISTER_SIZE)
{
- bytes_reserved += 4;
- offset[i] += 4;
+ bytes_reserved += REGISTER_SIZE;
+ offset[i] += REGISTER_SIZE;
}
}
}
- /* now move up the sp to reserve at least 4 words required for the args,
- or more than this if needed */
- /* wee also need to keep the sp aligned to 8 bytes */
+ /* CUM_BYTES_RESERVED 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. */
cum_bytes_aligned = STACK_ALIGN (cum_bytes_reserved);
- sp += max (cum_bytes_aligned, 16);
+ sp += max (cum_bytes_aligned, REG_PARM_STACK_SPACE);
- /* now write each of the args at the proper offset down the stack */
+ /* Now write each of the args at the proper offset down the stack.
+ ?!? We need to promote values to a full register instead of skipping
+ words in the stack. */
for (i = 0; i < nargs; i++)
write_memory (sp - offset[i], VALUE_CONTENTS (args[i]), lengths[i]);
-
- /* if a structure has to be returned, set up register 28 to hold its address */
+ /* If a structure has to be returned, set up register 28 to hold its
+ address */
if (struct_return)
write_register (28, struct_addr);
- /* the stack will have other 8 words on top of the args */
+ /* The stack will have 32 bytes of additional space for a frame marker. */
return sp + 32;
}
+#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
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. */
-value_ptr
-hppa_value_returned_from_stack (valtype, addr)
- register struct type *valtype;
- CORE_ADDR addr;
+struct value *
+hppa_value_returned_from_stack (register struct type *valtype, CORE_ADDR addr)
{
- register value_ptr val;
+ register struct value *val;
val = allocate_value (valtype);
CHECK_TYPEDEF (valtype);
man entry for shl_findsym */
CORE_ADDR
-find_stub_with_shl_get (function, handle)
- struct minimal_symbol *function;
- CORE_ADDR handle;
+find_stub_with_shl_get (struct minimal_symbol *function, CORE_ADDR handle)
{
struct symbol *get_sym, *symbol2;
struct minimal_symbol *buff_minsym, *msymbol;
struct type *ftype;
- value_ptr *args;
- value_ptr funcval, val;
+ struct value **args;
+ struct value *funcval;
+ struct value *val;
int x, namelen, err_value, tmp = -1;
CORE_ADDR endo_buff_addr, value_return_addr, errno_return_addr;
CORE_ADDR stub_addr;
- args = (value_ptr *) alloca (sizeof (value_ptr) * 8); /* 6 for the arguments and one null one??? */
+ args = alloca (sizeof (struct value *) * 8); /* 6 for the arguments and one null one??? */
funcval = find_function_in_inferior ("__d_shl_get");
get_sym = lookup_symbol ("__d_shl_get", NULL, VAR_NAMESPACE, NULL, NULL);
buff_minsym = lookup_minimal_symbol ("__buffer", NULL, NULL);
msymbol = lookup_minimal_symbol ("__shldp", NULL, NULL);
symbol2 = lookup_symbol ("__shldp", NULL, VAR_NAMESPACE, NULL, NULL);
endo_buff_addr = SYMBOL_VALUE_ADDRESS (buff_minsym);
- namelen = strlen (SYMBOL_NAME (function));
+ namelen = strlen (DEPRECATED_SYMBOL_NAME (function));
value_return_addr = endo_buff_addr + namelen;
ftype = check_typedef (SYMBOL_TYPE (get_sym));
/* set up stuff needed by __d_shl_get in buffer in end.o */
- target_write_memory (endo_buff_addr, SYMBOL_NAME (function), namelen);
+ target_write_memory (endo_buff_addr, DEPRECATED_SYMBOL_NAME (function), namelen);
target_write_memory (value_return_addr, (char *) &tmp, 4);
/* now prepare the arguments for the call */
args[0] = value_from_longest (TYPE_FIELD_TYPE (ftype, 0), 12);
- args[1] = value_from_longest (TYPE_FIELD_TYPE (ftype, 1), SYMBOL_VALUE_ADDRESS (msymbol));
- args[2] = value_from_longest (TYPE_FIELD_TYPE (ftype, 2), endo_buff_addr);
+ args[1] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 1), SYMBOL_VALUE_ADDRESS (msymbol));
+ args[2] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 2), endo_buff_addr);
args[3] = value_from_longest (TYPE_FIELD_TYPE (ftype, 3), TYPE_PROCEDURE);
- args[4] = value_from_longest (TYPE_FIELD_TYPE (ftype, 4), value_return_addr);
- args[5] = value_from_longest (TYPE_FIELD_TYPE (ftype, 5), errno_return_addr);
+ args[4] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 4), value_return_addr);
+ args[5] = value_from_pointer (TYPE_FIELD_TYPE (ftype, 5), errno_return_addr);
/* now call the function */
target_read_memory (value_return_addr, (char *) &stub_addr, sizeof (stub_addr));
if (stub_addr <= 0)
- error ("call to __d_shl_get failed, error code is %d", err_value); /* purecov: deadcode */
+ error ("call to __d_shl_get failed, error code is %d", err_value);
return (stub_addr);
}
/* Cover routine for find_stub_with_shl_get to pass to catch_errors */
static int
-cover_find_stub_with_shl_get (PTR args_untyped)
+cover_find_stub_with_shl_get (void *args_untyped)
{
args_for_find_stub *args = args_untyped;
args->return_val = find_stub_with_shl_get (args->msym, args->solib_handle);
Please contact Jeff Law (law@cygnus.com) before changing this code. */
CORE_ADDR
-hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
- char *dummy;
- CORE_ADDR pc;
- CORE_ADDR fun;
- int nargs;
- value_ptr *args;
- struct type *type;
- int gcc_p;
+hppa_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ struct value **args, struct type *type, int gcc_p)
{
CORE_ADDR dyncall_addr;
struct minimal_symbol *msymbol;
CORE_ADDR solib_handle = 0;
/* Nonzero if we will use GCC's PLT call routine. This routine must be
- passed an import stub, not a PLABEL. It is also necessary to set %r19
- (the PIC register) before performing the call.
+ passed an import stub, not a PLABEL. It is also necessary to set %r19
+ (the PIC register) before performing the call.
If zero, then we are using __d_plt_call (HP's PLT call routine) or we
are calling the target directly. When using __d_plt_call we want to
use a PLABEL instead of an import stub. */
int using_gcc_plt_call = 1;
+#ifdef GDB_TARGET_IS_HPPA_20W
+ /* We currently use completely different code for the PA2.0W inferior
+ function call sequences. This needs to be cleaned up. */
+ {
+ CORE_ADDR pcsqh, pcsqt, pcoqh, pcoqt, sr5;
+ struct target_waitstatus w;
+ int inst1, inst2;
+ char buf[4];
+ int status;
+ struct objfile *objfile;
+
+ /* We can not modify the PC space queues directly, so we start
+ up the inferior and execute a couple instructions to set the
+ space queues so that they point to the call dummy in the stack. */
+ pcsqh = read_register (PCSQ_HEAD_REGNUM);
+ sr5 = read_register (SR5_REGNUM);
+ if (1)
+ {
+ pcoqh = read_register (PCOQ_HEAD_REGNUM);
+ pcoqt = read_register (PCOQ_TAIL_REGNUM);
+ if (target_read_memory (pcoqh, buf, 4) != 0)
+ error ("Couldn't modify space queue\n");
+ inst1 = extract_unsigned_integer (buf, 4);
+
+ if (target_read_memory (pcoqt, buf, 4) != 0)
+ error ("Couldn't modify space queue\n");
+ inst2 = extract_unsigned_integer (buf, 4);
+
+ /* BVE (r1) */
+ *((int *) buf) = 0xe820d000;
+ if (target_write_memory (pcoqh, buf, 4) != 0)
+ error ("Couldn't modify space queue\n");
+
+ /* NOP */
+ *((int *) buf) = 0x08000240;
+ if (target_write_memory (pcoqt, buf, 4) != 0)
+ {
+ *((int *) buf) = inst1;
+ target_write_memory (pcoqh, buf, 4);
+ error ("Couldn't modify space queue\n");
+ }
+
+ write_register (1, pc);
+
+ /* Single step twice, the BVE instruction will set the space queue
+ such that it points to the PC value written immediately above
+ (ie the call dummy). */
+ resume (1, 0);
+ target_wait (inferior_ptid, &w);
+ resume (1, 0);
+ target_wait (inferior_ptid, &w);
+
+ /* Restore the two instructions at the old PC locations. */
+ *((int *) buf) = inst1;
+ target_write_memory (pcoqh, buf, 4);
+ *((int *) buf) = inst2;
+ target_write_memory (pcoqt, buf, 4);
+ }
+
+ /* The call dummy wants the ultimate destination address initially
+ in register %r5. */
+ write_register (5, fun);
+
+ /* We need to see if this objfile has a different DP value than our
+ own (it could be a shared library for example). */
+ ALL_OBJFILES (objfile)
+ {
+ struct obj_section *s;
+ obj_private_data_t *obj_private;
+
+ /* See if FUN is in any section within this shared library. */
+ for (s = objfile->sections; s < objfile->sections_end; s++)
+ if (s->addr <= fun && fun < s->endaddr)
+ break;
+
+ if (s >= objfile->sections_end)
+ continue;
+
+ obj_private = (obj_private_data_t *) objfile->obj_private;
+
+ /* The DP value may be different for each objfile. But within an
+ objfile each function uses the same dp value. Thus we do not need
+ to grope around the opd section looking for dp values.
+
+ ?!? This is not strictly correct since we may be in a shared library
+ and want to call back into the main program. To make that case
+ work correctly we need to set obj_private->dp for the main program's
+ objfile, then remove this conditional. */
+ if (obj_private->dp)
+ write_register (27, obj_private->dp);
+ break;
+ }
+ return pc;
+ }
+#endif
+
+#ifndef GDB_TARGET_IS_HPPA_20W
/* Prefer __gcc_plt_call over the HP supplied routine because
__gcc_plt_call works for any number of arguments. */
trampoline = NULL;
/* Get the GOT/DP value for the target function. It's
at *(fun+4). Note the call dummy is *NOT* allowed to
trash %r19 before calling the target function. */
- write_register (19, read_memory_integer ((fun & ~0x3) + 4, 4));
+ write_register (19, read_memory_integer ((fun & ~0x3) + 4,
+ REGISTER_SIZE));
/* Now get the real address for the function we are calling, it's
at *fun. */
- fun = (CORE_ADDR) read_memory_integer (fun & ~0x3, 4);
+ fun = (CORE_ADDR) read_memory_integer (fun & ~0x3,
+ TARGET_PTR_BIT / 8);
}
else
{
stub rather than the export stub or real function for lazy binding
to work correctly
- /* If we are using the gcc PLT call routine, then we need to
+ If we are using the gcc PLT call routine, then we need to
get the import stub for the target function. */
if (using_gcc_plt_call && som_solib_get_got_by_pc (fun))
{
funsymbol = lookup_minimal_symbol_by_pc (fun);
if (!funsymbol)
- error ("Unable to find minimal symbol for target fucntion.\n");
+ error ("Unable to find minimal symbol for target function.\n");
/* Search all the object files for an import symbol with the
right name. */
{
stub_symbol
= lookup_minimal_symbol_solib_trampoline
- (SYMBOL_NAME (funsymbol), NULL, objfile);
+ (DEPRECATED_SYMBOL_NAME (funsymbol), NULL, objfile);
if (!stub_symbol)
- stub_symbol = lookup_minimal_symbol (SYMBOL_NAME (funsymbol),
+ stub_symbol = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (funsymbol),
NULL, objfile);
/* Found a symbol with the right name. */
/* It must also be an import stub. */
u = find_unwind_entry (SYMBOL_VALUE (stub_symbol));
- if (!u
- || (u->stub_unwind.stub_type != IMPORT)
- && u->stub_unwind.stub_type != IMPORT_SHLIB)
+ if (u == NULL
+ || (u->stub_unwind.stub_type != IMPORT
+#ifdef GDB_NATIVE_HPUX_11
+ /* Sigh. The hpux 10.20 dynamic linker will blow
+ chunks if we perform a call to an unbound function
+ via the IMPORT_SHLIB stub. The hpux 11.00 dynamic
+ linker will blow chunks if we do not call the
+ unbound function via the IMPORT_SHLIB stub.
+
+ We currently have no way to select bevahior on just
+ the target. However, we only support HPUX/SOM in
+ native mode. So we conditinalize on a native
+ #ifdef. Ugly. Ugly. Ugly */
+ && u->stub_unwind.stub_type != IMPORT_SHLIB
+#endif
+ ))
continue;
/* OK. Looks like the correct import stub. */
newfun = SYMBOL_VALUE (stub_symbol);
fun = newfun;
+
+ /* If we found an IMPORT stub, then we want to stop
+ searching now. If we found an IMPORT_SHLIB, we want
+ to continue the search in the hopes that we will find
+ an IMPORT stub. */
+ if (u->stub_unwind.stub_type == IMPORT)
+ break;
}
}
new_stub = find_stub_with_shl_get (fmsymbol, solib_handle);
if (new_stub == 0)
- error ("Can't find an import stub for %s", SYMBOL_NAME (fmsymbol));
+ error ("Can't find an import stub for %s", DEPRECATED_SYMBOL_NAME (fmsymbol));
/* We have to store the address of the stub in __shlib_funcptr. */
msymbol = lookup_minimal_symbol ("__shlib_funcptr", NULL,
}
}
-#ifndef GDB_TARGET_IS_HPPA_20W
/* Store upper 21 bits of function address into ldil. fun will either be
the final target (most cases) or __d_plt_call when calling into a shared
library and __gcc_plt_call is not available. */
deposit_14 (fun & MASK_11,
extract_unsigned_integer (&dummy[FUNC_LDO_OFFSET],
INSTRUCTION_SIZE)));
-#endif /* GDB_TARGET_IS_HPPA_20W */
#ifdef SR4EXPORT_LDIL_OFFSET
{
if (flags & 2)
return pc;
#ifndef GDB_TARGET_IS_PA_ELF
- else if (som_solib_get_got_by_pc (target_read_pc (inferior_pid)))
+ else if (som_solib_get_got_by_pc (hppa_target_read_pc (inferior_ptid)))
return pc;
#endif
else
return dyncall_addr;
+#endif
}
-
-
-
/* If the pid is in a syscall, then the FP register is not readable.
We'll return zero in that case, rather than attempting to read it
and cause a warning. */
+
CORE_ADDR
-target_read_fp (pid)
- int pid;
+hppa_read_fp (int pid)
{
int flags = read_register (FLAGS_REGNUM);
return read_register (FP_REGNUM);
}
+CORE_ADDR
+hppa_target_read_fp (void)
+{
+ return hppa_read_fp (PIDGET (inferior_ptid));
+}
/* Get the PC from %r31 if currently in a syscall. Also mask out privilege
bits. */
CORE_ADDR
-target_read_pc (pid)
- int pid;
+hppa_target_read_pc (ptid_t ptid)
{
- int flags = read_register_pid (FLAGS_REGNUM, pid);
+ int flags = read_register_pid (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, pid) & ~0x3;
+ return read_register_pid (31, ptid) & ~0x3;
- return read_register_pid (PC_REGNUM, pid) & ~0x3;
+ return read_register_pid (PC_REGNUM, ptid) & ~0x3;
}
/* Write out the PC. If currently in a syscall, then also write the new
PC value into %r31. */
void
-target_write_pc (v, pid)
- CORE_ADDR v;
- int pid;
+hppa_target_write_pc (CORE_ADDR v, ptid_t ptid)
{
- int flags = read_register_pid (FLAGS_REGNUM, pid);
+ int flags = read_register_pid (FLAGS_REGNUM, ptid);
/* The following test does not belong here. It is OS-specific, and belongs
in native code. */
privilege bits set correctly. */
/* Test SS_INSYSCALL */
if (flags & 2)
- write_register_pid (31, v | 0x3, pid);
+ write_register_pid (31, v | 0x3, ptid);
- write_register_pid (PC_REGNUM, v, pid);
- write_register_pid (NPC_REGNUM, v + 4, pid);
+ write_register_pid (PC_REGNUM, v, ptid);
+ write_register_pid (NPC_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 (type)
- struct type *type;
+hppa_alignof (struct type *type)
{
int max_align, align, i;
CHECK_TYPEDEF (type);
/* Print the register regnum, or all registers if regnum is -1 */
void
-pa_do_registers_info (regnum, fpregs)
- int regnum;
- int fpregs;
+pa_do_registers_info (int regnum, int fpregs)
{
char raw_regs[REGISTER_BYTES];
int i;
/* Make a copy of gdb's save area (may cause actual
reads from the target). */
for (i = 0; i < NUM_REGS; i++)
- read_relative_register_raw_bytes (i, raw_regs + REGISTER_BYTE (i));
+ frame_register_read (deprecated_selected_frame, i, raw_regs + REGISTER_BYTE (i));
if (regnum == -1)
pa_print_registers (raw_regs, regnum, fpregs);
if (!is_pa_2)
{
- printf_unfiltered ("%s %x\n", REGISTER_NAME (regnum), reg_val[1]);
+ printf_unfiltered ("%s %lx\n", REGISTER_NAME (regnum), reg_val[1]);
}
else
{
/* Fancy % formats to prevent leading zeros. */
if (reg_val[0] == 0)
- printf_unfiltered ("%s %x\n", REGISTER_NAME (regnum), reg_val[1]);
+ printf_unfiltered ("%s %lx\n", REGISTER_NAME (regnum), reg_val[1]);
else
- printf_unfiltered ("%s %x%8.8x\n", REGISTER_NAME (regnum),
+ printf_unfiltered ("%s %lx%8.8lx\n", REGISTER_NAME (regnum),
reg_val[0], reg_val[1]);
}
}
/********** new function ********************/
void
-pa_do_strcat_registers_info (regnum, fpregs, stream, precision)
- int regnum;
- int fpregs;
- GDB_FILE *stream;
- enum precision_type precision;
+pa_do_strcat_registers_info (int regnum, int fpregs, struct ui_file *stream,
+ enum precision_type precision)
{
char raw_regs[REGISTER_BYTES];
int i;
/* Make a copy of gdb's save area (may cause actual
reads from the target). */
for (i = 0; i < NUM_REGS; i++)
- read_relative_register_raw_bytes (i, raw_regs + REGISTER_BYTE (i));
+ frame_register_read (deprecated_selected_frame, i, raw_regs + REGISTER_BYTE (i));
if (regnum == -1)
pa_strcat_registers (raw_regs, regnum, fpregs, stream);
if (!is_pa_2)
{
- fprintf_unfiltered (stream, "%s %x", REGISTER_NAME (regnum), reg_val[1]);
+ fprintf_unfiltered (stream, "%s %lx", REGISTER_NAME (regnum), reg_val[1]);
}
else
{
/* Fancy % formats to prevent leading zeros. */
if (reg_val[0] == 0)
- fprintf_unfiltered (stream, "%s %x", REGISTER_NAME (regnum),
+ fprintf_unfiltered (stream, "%s %lx", REGISTER_NAME (regnum),
reg_val[1]);
else
- fprintf_unfiltered (stream, "%s %x%8.8x", REGISTER_NAME (regnum),
+ fprintf_unfiltered (stream, "%s %lx%8.8lx", REGISTER_NAME (regnum),
reg_val[0], reg_val[1]);
}
}
Note that reg_val is really expected to be an array of longs,
with two elements. */
static void
-pa_register_look_aside (raw_regs, regnum, raw_val)
- char *raw_regs;
- int regnum;
- long *raw_val;
+pa_register_look_aside (char *raw_regs, int regnum, long *raw_val)
{
static int know_which = 0; /* False */
int start;
- char buf[MAX_REGISTER_RAW_SIZE];
+ char *buf = alloca (max_register_size (current_gdbarch));
long long reg_val;
if (!know_which)
for (i = start; i < 2; i++)
{
errno = 0;
- raw_val[i] = call_ptrace (PT_RUREGS, inferior_pid,
+ raw_val[i] = call_ptrace (PT_RUREGS, PIDGET (inferior_ptid),
(PTRACE_ARG3_TYPE) regaddr, 0);
if (errno != 0)
{
/* "Info all-reg" command */
static void
-pa_print_registers (raw_regs, regnum, fpregs)
- char *raw_regs;
- int regnum;
- int fpregs;
+pa_print_registers (char *raw_regs, int regnum, int fpregs)
{
int i, j;
/* Alas, we are compiled so that "long long" is 32 bits */
/* Being big-endian, on this machine the low bits
(the ones we want to look at) are in the second longword. */
long_val = extract_signed_integer (&raw_val[1], 4);
- printf_filtered ("%10.10s: %8x ",
+ printf_filtered ("%10.10s: %8lx ",
REGISTER_NAME (regnum), long_val);
}
else
{
/* raw_val = extract_signed_integer(&raw_val, 8); */
if (raw_val[0] == 0)
- printf_filtered ("%10.10s: %8x ",
+ printf_filtered ("%10.10s: %8lx ",
REGISTER_NAME (regnum), raw_val[1]);
else
- printf_filtered ("%10.10s: %8x%8.8x ",
+ printf_filtered ("%10.10s: %8lx%8.8lx ",
REGISTER_NAME (regnum),
raw_val[0], raw_val[1]);
}
/************* new function ******************/
static void
-pa_strcat_registers (raw_regs, regnum, fpregs, stream)
- char *raw_regs;
- int regnum;
- int fpregs;
- GDB_FILE *stream;
+pa_strcat_registers (char *raw_regs, int regnum, int fpregs,
+ struct ui_file *stream)
{
int i, j;
long raw_val[2]; /* Alas, we are compiled so that "long long" is 32 bits */
/* Being big-endian, on this machine the low bits
(the ones we want to look at) are in the second longword. */
long_val = extract_signed_integer (&raw_val[1], 4);
- fprintf_filtered (stream, "%8.8s: %8x ", REGISTER_NAME (i + (j * 18)), long_val);
+ fprintf_filtered (stream, "%8.8s: %8lx ",
+ REGISTER_NAME (i + (j * 18)), long_val);
}
else
{
/* raw_val = extract_signed_integer(&raw_val, 8); */
if (raw_val[0] == 0)
- fprintf_filtered (stream, "%8.8s: %8x ", REGISTER_NAME (i + (j * 18)),
- raw_val[1]);
+ fprintf_filtered (stream, "%8.8s: %8lx ",
+ REGISTER_NAME (i + (j * 18)), raw_val[1]);
else
- fprintf_filtered (stream, "%8.8s: %8x%8.8x ", REGISTER_NAME (i + (j * 18)),
- raw_val[0], raw_val[1]);
+ fprintf_filtered (stream, "%8.8s: %8lx%8.8lx ",
+ REGISTER_NAME (i + (j * 18)), raw_val[0],
+ raw_val[1]);
}
}
fprintf_unfiltered (stream, "\n");
}
static void
-pa_print_fp_reg (i)
- int i;
+pa_print_fp_reg (int i)
{
- char raw_buffer[MAX_REGISTER_RAW_SIZE];
- char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ char *raw_buffer = alloca (max_register_size (current_gdbarch));
+ char *virtual_buffer = alloca (max_register_size (current_gdbarch));
/* Get 32bits of data. */
- read_relative_register_raw_bytes (i, raw_buffer);
+ 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));
if ((i % 2) == 0)
{
/* Get the data in raw format for the 2nd half. */
- read_relative_register_raw_bytes (i + 1, raw_buffer);
+ 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,
/*************** new function ***********************/
static void
-pa_strcat_fp_reg (i, stream, precision)
- int i;
- GDB_FILE *stream;
- enum precision_type precision;
+pa_strcat_fp_reg (int i, struct ui_file *stream, enum precision_type precision)
{
- char raw_buffer[MAX_REGISTER_RAW_SIZE];
- char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
+ char *raw_buffer = alloca (max_register_size (current_gdbarch));
+ char *virtual_buffer = alloca (max_register_size (current_gdbarch));
fputs_filtered (REGISTER_NAME (i), stream);
print_spaces_filtered (8 - strlen (REGISTER_NAME (i)), stream);
/* Get 32bits of data. */
- read_relative_register_raw_bytes (i, raw_buffer);
+ 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));
if (precision == double_precision && (i % 2) == 0)
{
- char raw_buf[MAX_REGISTER_RAW_SIZE];
+ char *raw_buf = alloca (max_register_size (current_gdbarch));
/* Get the data in raw format for the 2nd half. */
- read_relative_register_raw_bytes (i + 1, raw_buf);
+ 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));
just shared library trampolines (import, export). */
int
-in_solib_call_trampoline (pc, name)
- CORE_ADDR pc;
- char *name;
+hppa_in_solib_call_trampoline (CORE_ADDR pc, char *name)
{
struct minimal_symbol *minsym;
struct unwind_table_entry *u;
static CORE_ADDR dyncall = 0;
static CORE_ADDR sr4export = 0;
-/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
- new exec file */
+#ifdef GDB_TARGET_IS_HPPA_20W
+ /* PA64 has a completely different stub/trampoline scheme. Is it
+ better? Maybe. It's certainly harder to determine with any
+ certainty that we are in a stub because we can not refer to the
+ unwinders to help.
+
+ The heuristic is simple. Try to lookup the current PC value in th
+ minimal symbol table. If that fails, then assume we are not in a
+ stub and return.
+
+ Then see if the PC value falls within the section bounds for the
+ section containing the minimal symbol we found in the first
+ step. If it does, then assume we are not in a stub and return.
+
+ Finally peek at the instructions to see if they look like a stub. */
+ {
+ struct minimal_symbol *minsym;
+ asection *sec;
+ CORE_ADDR addr;
+ int insn, i;
+
+ minsym = lookup_minimal_symbol_by_pc (pc);
+ if (! minsym)
+ return 0;
+
+ sec = SYMBOL_BFD_SECTION (minsym);
+
+ if (sec->vma <= pc
+ && sec->vma + sec->_cooked_size < pc)
+ return 0;
+
+ /* We might be in a stub. Peek at the instructions. Stubs are 3
+ instructions long. */
+ insn = read_memory_integer (pc, 4);
+
+ /* Find out where we think we are within the stub. */
+ if ((insn & 0xffffc00e) == 0x53610000)
+ addr = pc;
+ else if ((insn & 0xffffffff) == 0xe820d000)
+ addr = pc - 4;
+ else if ((insn & 0xffffc00e) == 0x537b0000)
+ addr = pc - 8;
+ else
+ return 0;
+
+ /* Now verify each insn in the range looks like a stub instruction. */
+ insn = read_memory_integer (addr, 4);
+ if ((insn & 0xffffc00e) != 0x53610000)
+ return 0;
+
+ /* Now verify each insn in the range looks like a stub instruction. */
+ insn = read_memory_integer (addr + 4, 4);
+ if ((insn & 0xffffffff) != 0xe820d000)
+ return 0;
+
+ /* Now verify each insn in the range looks like a stub instruction. */
+ insn = read_memory_integer (addr + 8, 4);
+ if ((insn & 0xffffc00e) != 0x537b0000)
+ return 0;
+
+ /* Looks like a stub. */
+ return 1;
+ }
+#endif
+
+ /* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
+ new exec file */
/* First see if PC is in one of the two C-library trampolines. */
if (!dyncall)
if (pc == dyncall || pc == sr4export)
return 1;
+ minsym = lookup_minimal_symbol_by_pc (pc);
+ if (minsym && strcmp (DEPRECATED_SYMBOL_NAME (minsym), ".stub") == 0)
+ return 1;
+
/* Get the unwind descriptor corresponding to PC, return zero
if no unwind was found. */
u = find_unwind_entry (pc);
}
/* Should never happen. */
- warning ("Unable to find branch in parameter relocation stub.\n"); /* purecov: deadcode */
- return 0; /* purecov: deadcode */
+ warning ("Unable to find branch in parameter relocation stub.\n");
+ return 0;
}
/* Unknown stub type. For now, just return zero. */
- return 0; /* purecov: deadcode */
+ return 0;
}
/* Return one if PC is in the return path of a trampoline, else return zero.
just shared library trampolines (import, export). */
int
-in_solib_return_trampoline (pc, name)
- CORE_ADDR pc;
- char *name;
+hppa_in_solib_return_trampoline (CORE_ADDR pc, char *name)
{
struct unwind_table_entry *u;
}
/* Should never happen. */
- warning ("Unable to find branch in parameter relocation stub.\n"); /* purecov: deadcode */
- return 0; /* purecov: deadcode */
+ warning ("Unable to find branch in parameter relocation stub.\n");
+ return 0;
}
/* Unknown stub type. For now, just return zero. */
- return 0; /* purecov: deadcode */
+ return 0;
}
calling an argument relocation stub. It even handles some stubs
used in dynamic executables. */
-#if 0
CORE_ADDR
-skip_trampoline_code (pc, name)
- CORE_ADDR pc;
- char *name;
-{
- return find_solib_trampoline_target (pc);
-}
-
-#endif
-
-CORE_ADDR
-skip_trampoline_code (pc, name)
- CORE_ADDR pc;
- char *name;
+hppa_skip_trampoline_code (CORE_ADDR pc)
{
long orig_pc = pc;
long prev_inst, curr_inst, loc;
struct minimal_symbol *msym;
struct unwind_table_entry *u;
-
-/* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
- new exec file */
+ /* FIXME XXX - dyncall and sr4export must be initialized whenever we get a
+ new exec file */
if (!dyncall)
{
the PLT entry for this function, not the address of the function
itself. Bit 31 has meaning too, but only for MPE. */
if (pc & 0x2)
- pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, 4);
+ pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
}
if (pc == dyncall_external)
{
pc = (CORE_ADDR) read_register (22);
- pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, 4);
+ pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8);
}
else if (pc == sr4export)
pc = (CORE_ADDR) (read_register (22));
ALL_MSYMBOLS (objfile, msymbol)
{
if (MSYMBOL_TYPE (msymbol) == mst_text
- && STREQ (SYMBOL_NAME (msymbol), SYMBOL_NAME (msym)))
+ && STREQ (DEPRECATED_SYMBOL_NAME (msymbol), DEPRECATED_SYMBOL_NAME (msym)))
{
function_found = 1;
break;
stubsym = lookup_minimal_symbol_by_pc (loc);
if (stubsym == NULL)
{
- warning ("Unable to find symbol for 0x%x", loc);
+ warning ("Unable to find symbol for 0x%lx", loc);
return orig_pc == pc ? 0 : pc & ~0x3;
}
- libsym = lookup_minimal_symbol (SYMBOL_NAME (stubsym), NULL, NULL);
+ libsym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (stubsym), NULL, NULL);
if (libsym == NULL)
{
warning ("Unable to find library symbol for %s\n",
- SYMBOL_NAME (stubsym));
+ DEPRECATED_SYMBOL_NAME (stubsym));
return orig_pc == pc ? 0 : pc & ~0x3;
}
else if ((curr_inst & 0xffe0f000) == 0xe840d000)
{
return (read_memory_integer
- (read_register (SP_REGNUM) - 24, 4)) & ~0x3;
+ (read_register (SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
}
/* What about be,n 0(sr0,%rp)? It's just another way we return to
I guess we could check for the previous instruction being
mtsp %r1,%sr0 if we want to do sanity checking. */
return (read_memory_integer
- (read_register (SP_REGNUM) - 24, 4)) & ~0x3;
+ (read_register (SP_REGNUM) - 24, TARGET_PTR_BIT / 8)) & ~0x3;
}
/* Haven't found the branch yet, but we're still in the stub.
This only handles instructions commonly found in prologues. */
static int
-prologue_inst_adjust_sp (inst)
- unsigned long inst;
+prologue_inst_adjust_sp (unsigned long inst)
{
/* This must persist across calls. */
static int save_high21;
if ((inst & 0xffe00000) == 0x6fc00000)
return 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)
/* Return nonzero if INST is a branch of some kind, else return zero. */
static int
-is_branch (inst)
- unsigned long inst;
+is_branch (unsigned long inst)
{
switch (inst >> 26)
{
zero it INST does not save a GR. */
static int
-inst_saves_gr (inst)
- unsigned long inst;
+inst_saves_gr (unsigned long inst)
{
/* Does it look like a stw? */
if ((inst >> 26) == 0x1a || (inst >> 26) == 0x1b
FIXME: What about argument stores with the HP compiler in ANSI mode? */
static int
-inst_saves_fr (inst)
- unsigned long inst;
+inst_saves_fr (unsigned long inst)
{
/* is this an FSTD ? */
if ((inst & 0xfc00dfc0) == 0x2c001200)
CORE_ADDR
-skip_prologue_hard_way (pc)
- CORE_ADDR pc;
+skip_prologue_hard_way (CORE_ADDR pc)
{
char buf[4];
CORE_ADDR orig_pc = pc;
if (inst == 0x6bc23fd9 || inst == 0x0fc212c1)
save_rp = 0;
- /* This is the only way we save SP into the stack. At this time
+ /* 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)
+ 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;
+ }
+
/* Account for general and floating-point register saves. */
reg_num = inst_saves_gr (inst);
save_gr &= ~(1 << reg_num);
FIXME. Can still die if we have a mix of GR and FR argument
stores! */
- if (reg_num >= 23 && reg_num <= 26)
+ if (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
{
- while (reg_num >= 23 && reg_num <= 26)
+ while (reg_num >= (TARGET_PTR_BIT == 64 ? 19 : 23) && reg_num <= 26)
{
pc += 4;
status = target_read_memory (pc, buf, 4);
save. */
if ((inst & 0xfc000000) == 0x34000000
&& inst_saves_fr (next_inst) >= 4
- && inst_saves_fr (next_inst) <= 7)
+ && 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);
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 <= 7)
+ if (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
- while (reg_num >= 4 && reg_num <= 7)
+ while (reg_num >= 4 && reg_num <= (TARGET_PTR_BIT == 64 ? 11 : 7))
{
pc += 8;
status = target_read_memory (pc, buf, 4);
we can determine it from the debug symbols. Else return zero. */
static CORE_ADDR
-after_prologue (pc)
- CORE_ADDR pc;
+after_prologue (CORE_ADDR pc)
{
struct symtab_and_line sal;
CORE_ADDR func_addr, func_end;
stuff some day. */
CORE_ADDR
-hppa_skip_prologue (pc)
- CORE_ADDR pc;
+hppa_skip_prologue (CORE_ADDR pc)
{
unsigned long inst;
int offset;
the address we return for it IS the sp for the next frame. */
void
-hppa_frame_find_saved_regs (frame_info, frame_saved_regs)
- struct frame_info *frame_info;
- struct frame_saved_regs *frame_saved_regs;
+hppa_frame_find_saved_regs (struct frame_info *frame_info,
+ struct frame_saved_regs *frame_saved_regs)
{
CORE_ADDR pc;
struct unwind_table_entry *u;
int status, i, reg;
char buf[4];
int fp_loc = -1;
+ int final_iteration;
/* Zero out everything. */
memset (frame_saved_regs, '\0', sizeof (struct frame_saved_regs));
instead, let find_dummy_frame_regs fill in the correct offsets
for the saved registers. */
if ((frame_info->pc >= frame_info->frame
- && frame_info->pc <= (frame_info->frame + CALL_DUMMY_LENGTH
- + 32 * 4 + (NUM_REGS - FP0_REGNUM) * 8
- + 6 * 4)))
+ && frame_info->pc <= (frame_info->frame
+ /* A call dummy is sized in words, but it is
+ actually a series of instructions. Account
+ for that scaling factor. */
+ + ((REGISTER_SIZE / INSTRUCTION_SIZE)
+ * CALL_DUMMY_LENGTH)
+ /* Similarly we have to account for 64bit
+ wide register saves. */
+ + (32 * REGISTER_SIZE)
+ /* We always consider FP regs 8 bytes long. */
+ + (NUM_REGS - FP0_REGNUM) * 8
+ /* Similarly we have to account for 64bit
+ wide register saves. */
+ + (6 * REGISTER_SIZE))))
find_dummy_frame_regs (frame_info, frame_saved_regs);
/* Interrupt handlers are special too. They lay out the register
/* SP is a little special. */
if (i == SP_REGNUM)
frame_saved_regs->regs[SP_REGNUM]
- = read_memory_integer (frame_info->frame + SP_REGNUM * 4, 4);
+ = read_memory_integer (frame_info->frame + SP_REGNUM * 4,
+ TARGET_PTR_BIT / 8);
else
frame_saved_regs->regs[i] = frame_info->frame + i * 4;
}
#ifdef FRAME_FIND_SAVED_REGS_IN_SIGTRAMP
/* Handle signal handler callers. */
- if (frame_info->signal_handler_caller)
+ if ((get_frame_type (frame_info) == SIGTRAMP_FRAME))
{
FRAME_FIND_SAVED_REGS_IN_SIGTRAMP (frame_info, frame_saved_regs);
return;
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)
+ final_iteration = 0;
+ while ((save_gr || save_fr || save_rp || save_sp || stack_remaining > 0)
+ && pc <= frame_info->pc)
{
status = target_read_memory (pc, buf, 4);
inst = extract_unsigned_integer (buf, 4);
/* Note the interesting effects of this instruction. */
stack_remaining -= prologue_inst_adjust_sp (inst);
- /* There is only one instruction used for saving RP into the stack. */
- if (inst == 0x6bc23fd9)
+ /* There are limited ways to store the return pointer into the
+ stack. */
+ if (inst == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
{
save_rp = 0;
frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 20;
}
+ else if (inst == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
+ {
+ save_rp = 0;
+ frame_saved_regs->regs[RP_REGNUM] = frame_info->frame - 16;
+ }
- /* Just note that we found the save of SP into the stack. The
- value for frame_saved_regs was computed above. */
- if ((inst & 0xffffc000) == 0x6fc10000)
- save_sp = 0;
+ /* Note 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) */
+ {
+ frame_saved_regs->regs[FP_REGNUM] = frame_info->frame;
+ save_sp = 0;
+ }
/* Account for general and floating-point register saves. */
reg = inst_saves_gr (inst);
if ((inst >> 26) == 0x1b
&& extract_14 (inst) >= 0)
frame_saved_regs->regs[reg] = frame_info->frame;
+ /* A std has explicit post_modify forms. */
+ else if ((inst & 0xfc00000c0) == 0x70000008)
+ frame_saved_regs->regs[reg] = frame_info->frame;
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)
frame_saved_regs->regs[reg]
- = frame_info->frame + extract_14 (inst);
+ = frame_info->frame + offset;
else
frame_saved_regs->regs[reg]
- = frame_info->frame + (u->Total_frame_size << 3)
- + extract_14 (inst);
+ = (frame_info->frame + (u->Total_frame_size << 3)
+ + offset);
}
}
}
}
- /* 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))
+ /* 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;
+
/* Bump the PC. */
pc += 4;
}
0 => success
1 => failure */
int
-setup_d_pid_in_inferior ()
+setup_d_pid_in_inferior (void)
{
CORE_ADDR anaddr;
struct minimal_symbol *msymbol;
}
anaddr = SYMBOL_VALUE_ADDRESS (msymbol);
- store_unsigned_integer (buf, 4, inferior_pid); /* FIXME 32x64? */
+ store_unsigned_integer (buf, 4, PIDGET (inferior_ptid)); /* FIXME 32x64? */
if (target_write_memory (anaddr, buf, 4)) /* FIXME 32x64? */
{
warning ("Unable to write __d_pid");
1 => success */
static int
-initialize_hp_cxx_exception_support ()
+initialize_hp_cxx_exception_support (void)
{
struct symtabs_and_lines sals;
struct cleanup *old_chain;
return 0;
}
+#ifndef GDB_TARGET_IS_HPPA_20W
/* Check whether the executable is dynamically linked or archive bound */
/* With an archive-bound executable we can use the raw addresses we find
for the callback function, etc. without modification. For an executable
args.return_val = 0;
recurse++;
- catch_errors (cover_find_stub_with_shl_get, (PTR) &args, message,
+ catch_errors (cover_find_stub_with_shl_get, &args, message,
RETURN_MASK_ALL);
eh_notify_callback_addr = args.return_val;
recurse--;
if (!eh_notify_callback_addr)
{
/* We can get here either if there is no plabel in the export list
- for the main image, or if something strange happened (??) */
+ for the main image, or if something strange happened (?) */
warning ("Couldn't find a plabel (indirect function label) for the exception callback.");
warning ("GDB will not be able to intercept exception events.");
return 0;
}
else
exception_catchpoints_are_fragile = 0;
+#endif
/* Now, look for the breakpointable routine in end.o */
/* This should also be available in the SOM symbol dict. if end.o linked in */
address was found. */
struct symtab_and_line *
-child_enable_exception_callback (kind, enable)
- enum exception_event_kind kind;
- int enable;
+child_enable_exception_callback (enum exception_event_kind kind, int enable)
{
char buf[4];
if (enable)
{
/* Ensure that __d_pid is set up correctly -- end.c code checks this. :-( */
- if (inferior_pid > 0)
+ if (PIDGET (inferior_ptid) > 0)
{
if (setup_d_pid_in_inferior ())
return (struct symtab_and_line *) -1;
}
else
{
- warning ("Internal error: Invalid inferior pid? Cannot intercept exception events."); /* purecov: deadcode */
- return (struct symtab_and_line *) -1; /* purecov: deadcode */
+ warning ("Internal error: Invalid inferior pid? Cannot intercept exception events.");
+ return (struct symtab_and_line *) -1;
}
}
return (struct symtab_and_line *) -1;
}
break;
- default: /* purecov: deadcode */
- error ("Request to enable unknown or unsupported exception event."); /* purecov: deadcode */
+ default:
+ error ("Request to enable unknown or unsupported exception event.");
}
/* Copy break address into new sal struct, malloc'ing if needed. */
{
break_callback_sal = (struct symtab_and_line *) xmalloc (sizeof (struct symtab_and_line));
}
- INIT_SAL (break_callback_sal);
+ init_sal (break_callback_sal);
break_callback_sal->symtab = NULL;
break_callback_sal->pc = eh_break_addr;
break_callback_sal->line = 0;
and where it will be caught. More information may be reported
in the future */
struct exception_event_record *
-child_get_current_exception_event ()
+child_get_current_exception_event (void)
{
CORE_ADDR event_kind;
CORE_ADDR throw_addr;
if (level != 0)
return (struct exception_event_record *) NULL;
- select_frame (fi, -1);
+ select_frame (fi);
/* Read in the arguments */
/* __d_eh_notify_callback() is called with 3 arguments:
if (level != 0)
return (struct exception_event_record *) NULL;
- select_frame (fi, -1);
+ select_frame (fi);
throw_addr = fi->pc;
/* Go back to original (top) frame */
- select_frame (curr_frame, -1);
+ select_frame (curr_frame);
current_ex_event.kind = (enum exception_event_kind) event_kind;
current_ex_event.throw_sal = find_pc_line (throw_addr, 1);
return ¤t_ex_event;
}
+/* 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 void
-unwind_command (exp, from_tty)
- char *exp;
- int from_tty;
+unwind_command (char *exp, int from_tty)
{
CORE_ADDR address;
struct unwind_table_entry *u;
return;
}
- printf_unfiltered ("unwind_table_entry (0x%x):\n", u);
+ 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);
printf_unfiltered ("\n\tregion_end = ");
print_address (u->region_end, gdb_stdout);
-#ifdef __STDC__
#define pif(FLD) if (u->FLD) printf_unfiltered (" "#FLD);
-#else
-#define pif(FLD) if (u->FLD) printf_unfiltered (" FLD");
-#endif
printf_unfiltered ("\n\tflags =");
pif (Cannot_unwind);
putchar_unfiltered ('\n');
-#ifdef __STDC__
#define pin(FLD) printf_unfiltered ("\t"#FLD" = 0x%x\n", u->FLD);
-#else
-#define pin(FLD) printf_unfiltered ("\tFLD = 0x%x\n", u->FLD);
-#endif
pin (Region_description);
pin (Entry_FR);
For these reasons, we have to violate information hiding and
call "breakpoint_here_p". If core gdb thinks there is a bpt
here, that's what counts, as core gdb is the one which is
- putting the BPT instruction in and taking it out. */
+ putting the BPT instruction in and taking it out.
+
+ Note that this implementation is potentially redundant now that
+ default_prepare_to_proceed() has been added.
+
+ FIXME This may not support switching threads after Ctrl-C
+ correctly. The default implementation does support this. */
int
-hppa_prepare_to_proceed ()
+hppa_prepare_to_proceed (void)
{
pid_t old_thread;
pid_t current_thread;
- old_thread = hppa_switched_threads (inferior_pid);
+ old_thread = hppa_switched_threads (PIDGET (inferior_ptid));
if (old_thread != 0)
{
/* Switched over from "old_thread". Try to do
/* Yuk, shouldn't use global to specify current
thread. But that's how gdb does it. */
- current_thread = inferior_pid;
- inferior_pid = old_thread;
+ current_thread = PIDGET (inferior_ptid);
+ inferior_ptid = pid_to_ptid (old_thread);
new_pc = read_pc ();
if (new_pc != old_pc /* If at same pc, no need */
registers_changed ();
#if 0
printf ("---> PREPARE_TO_PROCEED (was %d, now %d)!\n",
- current_thread, inferior_pid);
+ current_thread, PIDGET (inferior_ptid));
#endif
return 1;
}
/* Otherwise switch back to the user-chosen thread. */
- inferior_pid = current_thread;
+ inferior_ptid = pid_to_ptid (current_thread);
new_pc = read_pc (); /* Re-prime register cache */
}
#endif /* PREPARE_TO_PROCEED */
void
-_initialize_hppa_tdep ()
+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 (PCOQ_HEAD_REGNUM, read_register (PCOQ_TAIL_REGNUM));
+ write_register (PCSQ_HEAD_REGNUM, read_register (PCSQ_TAIL_REGNUM));
+
+ write_register (PCOQ_TAIL_REGNUM, read_register (PCOQ_TAIL_REGNUM) + 4);
+ /* We can leave the tail's space the same, since there's no jump. */
+}
+
+/* Copy the function value from VALBUF into the proper location
+ for a function return.
+
+ Called only in the context of the "return" command. */
+
+void
+hppa_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,
+ so we always store the value into the integer registers.
+
+ If its a float value, then we also store it into the floating
+ point registers. */
+ deprecated_write_register_bytes (REGISTER_BYTE (28)
+ + (TYPE_LENGTH (type) > 4
+ ? (8 - TYPE_LENGTH (type))
+ : (4 - TYPE_LENGTH (type))),
+ valbuf, TYPE_LENGTH (type));
+ if (! SOFT_FLOAT && TYPE_CODE (type) == TYPE_CODE_FLT)
+ deprecated_write_register_bytes (REGISTER_BYTE (FP4_REGNUM),
+ valbuf, TYPE_LENGTH (type));
+}
+
+/* Copy the function's return value into VALBUF.
+
+ This function is called only in the context of "target function calls",
+ ie. when the debugger forces a function to be called in the child, and
+ when the debugger forces a fucntion to return prematurely via the
+ "return" command. */
+
+void
+hppa_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+ if (! SOFT_FLOAT && TYPE_CODE (type) == TYPE_CODE_FLT)
+ memcpy (valbuf,
+ (char *)regbuf + REGISTER_BYTE (FP4_REGNUM),
+ TYPE_LENGTH (type));
+ else
+ memcpy (valbuf,
+ ((char *)regbuf
+ + REGISTER_BYTE (28)
+ + (TYPE_LENGTH (type) > 4
+ ? (8 - TYPE_LENGTH (type))
+ : (4 - TYPE_LENGTH (type)))),
+ TYPE_LENGTH (type));
+}
+
+int
+hppa_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+ /* On the PA, any pass-by-value structure > 8 bytes is actually passed
+ via a pointer regardless of its type or the compiler used. */
+ return (TYPE_LENGTH (type) > 8);
+}
+
+int
+hppa_inner_than (CORE_ADDR lhs, CORE_ADDR rhs)
+{
+ /* Stack grows upward */
+ return (lhs > rhs);
+}
+
+CORE_ADDR
+hppa_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.
+ On hppa the sp must always be kept 64-bit aligned */
+ return ((sp % 8) ? (sp + 7) & -8 : sp);
+}
+
+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 (IPSW_REGNUM);
+ const int flags = (int) read_register (FLAGS_REGNUM);
+
+ return ((ipsw & 0x00200000) && !(flags & 0x2));
+}
+
+int
+hppa_register_raw_size (int reg_nr)
+{
+ /* All registers have the same size. */
+ return REGISTER_SIZE;
+}
+
+/* Index within the register vector of the first byte of the space i
+ used for register REG_NR. */
+
+int
+hppa_register_byte (int reg_nr)
+{
+ return reg_nr * 4;
+}
+
+/* Return the GDB type object for the "standard" data type of data
+ in register N. */
+
+struct type *
+hppa_register_virtual_type (int reg_nr)
+{
+ if (reg_nr < FP4_REGNUM)
+ return builtin_type_int;
+ else
+ return builtin_type_float;
+}
+
+/* Store the address of the place in which to copy the structure the
+ subroutine will return. This is called from call_function. */
+
+void
+hppa_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+ 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(). */
+
+int
+hppa_cannot_store_register (int regnum)
+{
+ return (regnum == 0
+ || regnum == PCSQ_HEAD_REGNUM
+ || (regnum >= PCSQ_TAIL_REGNUM && regnum < IPSW_REGNUM)
+ || (regnum > IPSW_REGNUM && regnum < FP4_REGNUM));
+
+}
+
+CORE_ADDR
+hppa_frame_args_address (struct frame_info *fi)
+{
+ return fi->frame;
+}
+
+CORE_ADDR
+hppa_frame_locals_address (struct frame_info *fi)
+{
+ return fi->frame;
+}
+
+int
+hppa_frame_num_args (struct frame_info *frame)
+{
+ /* We can't tell how many args there are now that the C compiler delays
+ popping them. */
+ return -1;
+}
+
+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);
+}
+
+static struct gdbarch *
+hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ 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;
+ }
+
+ /* find a candidate among the list of pre-declared architectures. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return (arches->gdbarch);
+
+ /* If none found, then allocate and initialize one. */
+ gdbarch = gdbarch_alloc (&info, NULL);
+
+ /* Hook in ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
+ set_gdbarch_reg_struct_has_addr (gdbarch, hppa_reg_struct_has_addr);
+ set_gdbarch_function_start_offset (gdbarch, 0);
+ 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_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_extra_stack_alignment_needed (gdbarch, 0);
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+ set_gdbarch_register_size (gdbarch, 4);
+ set_gdbarch_num_regs (gdbarch, hppa_num_regs);
+ set_gdbarch_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_register_raw_size (gdbarch, hppa_register_raw_size);
+ set_gdbarch_register_bytes (gdbarch, hppa_num_regs * 4);
+ set_gdbarch_register_byte (gdbarch, hppa_register_byte);
+ set_gdbarch_register_virtual_size (gdbarch, hppa_register_raw_size);
+ set_gdbarch_deprecated_max_register_raw_size (gdbarch, 4);
+ set_gdbarch_deprecated_max_register_virtual_size (gdbarch, 8);
+ set_gdbarch_register_virtual_type (gdbarch, hppa_register_virtual_type);
+ 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_address (gdbarch, hppa_frame_args_address);
+ set_gdbarch_frame_locals_address (gdbarch, hppa_frame_locals_address);
+ set_gdbarch_frame_num_args (gdbarch, hppa_frame_num_args);
+ 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_call_dummy_length (gdbarch, INSTRUCTION_SIZE * 28);
+ set_gdbarch_call_dummy_start_offset (gdbarch, 0);
+ /* set_gdbarch_fix_call_dummy (gdbarch, hppa_fix_call_dummy); */
+ set_gdbarch_push_arguments (gdbarch, hppa_push_arguments);
+ set_gdbarch_smash_text_address (gdbarch, hppa_smash_text_address);
+ set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+ set_gdbarch_read_pc (gdbarch, hppa_target_read_pc);
+ set_gdbarch_write_pc (gdbarch, hppa_target_write_pc);
+ set_gdbarch_read_fp (gdbarch, hppa_target_read_fp);
+
+ return gdbarch;
+}
+
+static void
+hppa_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+ /* Nothing to print for the moment. */
+}
+
+void
+_initialize_hppa_tdep (void)
+{
+ struct cmd_list_element *c;
+ void break_at_finish_command (char *arg, int from_tty);
+ void tbreak_at_finish_command (char *arg, int from_tty);
+ void break_at_finish_at_depth_command (char *arg, int from_tty);
+
+ gdbarch_register (bfd_arch_hppa, hppa_gdbarch_init, hppa_dump_tdep);
tm_print_insn = print_insn_hppa;
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);
}
+