/* Target-dependent code for the HP PA-RISC architecture.
- Copyright (C) 1986-2014 Free Software Foundation, Inc.
+ Copyright (C) 1986-2018 Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
#include "regcache.h"
#include "completer.h"
#include "osabi.h"
-#include "gdb_assert.h"
#include "arch-utils.h"
/* For argument passing to the inferior. */
#include "symtab.h"
#include "gdbtypes.h"
#include "objfiles.h"
#include "hppa-tdep.h"
+#include <algorithm>
static int hppa_debug = 0;
static const int hppa32_num_regs = 128;
static const int hppa64_num_regs = 96;
+/* We use the objfile->obj_private pointer for two things:
+ * 1. An unwind table;
+ *
+ * 2. A pointer to any associated shared library object.
+ *
+ * #defines are used to help refer to these objects.
+ */
+
+/* Info about the unwind table associated with an object file.
+ * This is hung off of the "objfile->obj_private" pointer, and
+ * is allocated in the objfile's psymbol obstack. This allows
+ * us to have unique unwind info for each executable and shared
+ * library that we are debugging.
+ */
+struct hppa_unwind_info
+ {
+ struct unwind_table_entry *table; /* Pointer to unwind info */
+ struct unwind_table_entry *cache; /* Pointer to last entry we found */
+ int last; /* Index of last entry */
+ };
+
+struct hppa_objfile_private
+ {
+ struct hppa_unwind_info *unwind_info; /* a pointer */
+ struct so_list *so_info; /* a pointer */
+ CORE_ADDR dp;
+
+ int dummy_call_sequence_reg;
+ CORE_ADDR dummy_call_sequence_addr;
+ };
+
/* hppa-specific object data -- unwind and solib info.
TODO/maybe: think about splitting this into two parts; the unwind data is
common to all hppa targets, but is only used in this file; we can register
that separately and make this static. The solib data is probably hpux-
specific, so we can create a separate extern objfile_data that is registered
by hppa-hpux-tdep.c and shared with pa64solib.c and somsolib.c. */
-const struct objfile_data *hppa_objfile_priv_data = NULL;
+static const struct objfile_data *hppa_objfile_priv_data = NULL;
/* Get at various relevent fields of an instruction word. */
#define MASK_5 0x1f
static int
hppa_sign_extend (unsigned val, unsigned bits)
{
- return (int) (val >> (bits - 1) ? (-1 << bits) | val : val);
+ return (int) (val >> (bits - 1) ? (-(1 << bits)) | val : val);
}
/* For many immediate values the sign bit is the low bit! */
static int
hppa_low_hppa_sign_extend (unsigned val, unsigned bits)
{
- return (int) ((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
+ return (int) ((val & 0x1 ? (-(1 << (bits - 1))) : 0) | val >> 1);
}
/* Extract the bits at positions between FROM and TO, using HP's numbering
CORE_ADDR
hppa_symbol_address(const char *sym)
{
- struct minimal_symbol *minsym;
+ struct bound_minimal_symbol minsym;
minsym = lookup_minimal_symbol (sym, NULL, NULL);
- if (minsym)
- return MSYMBOL_VALUE_ADDRESS (minsym);
+ if (minsym.minsym)
+ return BMSYMBOL_VALUE_ADDRESS (minsym);
else
return (CORE_ADDR)-1;
}
-struct hppa_objfile_private *
+static struct hppa_objfile_private *
hppa_init_objfile_priv_data (struct objfile *objfile)
{
struct hppa_objfile_private *priv;
static int
compare_unwind_entries (const void *arg1, const void *arg2)
{
- const struct unwind_table_entry *a = arg1;
- const struct unwind_table_entry *b = arg2;
+ const struct unwind_table_entry *a = (const struct unwind_table_entry *) arg1;
+ const struct unwind_table_entry *b = (const struct unwind_table_entry *) arg2;
if (a->region_start > b->region_start)
return 1;
static void
internalize_unwinds (struct objfile *objfile, struct unwind_table_entry *table,
asection *section, unsigned int entries,
- unsigned int size, CORE_ADDR text_offset)
+ size_t size, CORE_ADDR text_offset)
{
/* We will read the unwind entries into temporary memory, then
fill in the actual unwind table. */
struct gdbarch *gdbarch = get_objfile_arch (objfile);
unsigned long tmp;
unsigned i;
- char *buf = alloca (size);
+ char *buf = (char *) alloca (size);
CORE_ADDR low_text_segment_address;
/* For ELF targets, then unwinds are supposed to
read_unwind_info (struct objfile *objfile)
{
asection *unwind_sec, *stub_unwind_sec;
- unsigned unwind_size, stub_unwind_size, total_size;
+ size_t unwind_size, stub_unwind_size, total_size;
unsigned index, unwind_entries;
unsigned stub_entries, total_entries;
CORE_ADDR text_offset;
if (stub_unwind_size > 0)
{
unsigned int i;
- char *buf = alloca (stub_unwind_size);
+ char *buf = (char *) alloca (stub_unwind_size);
/* Read in the stub unwind entries. */
bfd_get_section_contents (objfile->obfd, stub_unwind_sec, buf,
{
struct hppa_unwind_info *ui;
ui = NULL;
- priv = objfile_data (objfile, hppa_objfile_priv_data);
+ priv = ((struct hppa_objfile_private *)
+ objfile_data (objfile, hppa_objfile_priv_data));
if (priv)
ui = ((struct hppa_objfile_private *) priv)->unwind_info;
if (!ui)
{
read_unwind_info (objfile);
- priv = objfile_data (objfile, hppa_objfile_priv_data);
+ priv = ((struct hppa_objfile_private *)
+ objfile_data (objfile, hppa_objfile_priv_data));
if (priv == NULL)
error (_("Internal error reading unwind information."));
ui = ((struct hppa_objfile_private *) priv)->unwind_info;
return NULL;
}
-/* The epilogue is defined here as the area either on the `bv' instruction
+/* Implement the stack_frame_destroyed_p gdbarch method.
+
+ The epilogue is defined here as the area either on the `bv' instruction
itself or an instruction which destroys the function's stack frame.
We do not assume that the epilogue is at the end of a function as we can
also have return sequences in the middle of a function. */
+
static int
-hppa_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+hppa_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
unsigned long status;
return 0;
}
-static const unsigned char *
-hppa_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pc, int *len)
-{
- static const unsigned char breakpoint[] = {0x00, 0x01, 0x00, 0x04};
- (*len) = sizeof (breakpoint);
- return breakpoint;
-}
+constexpr gdb_byte hppa_break_insn[] = {0x00, 0x01, 0x00, 0x04};
+
+typedef BP_MANIPULATION (hppa_break_insn) hppa_breakpoint;
/* Return the name of a register. */
static const char *
hppa32_register_name (struct gdbarch *gdbarch, int i)
{
- static char *names[] = {
+ static const char *names[] = {
"flags", "r1", "rp", "r3",
"r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11",
static const char *
hppa64_register_name (struct gdbarch *gdbarch, int i)
{
- static char *names[] = {
+ static const char *names[] = {
"flags", "r1", "rp", "r3",
"r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11",
hppa64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
/* The general registers and the sar are the same in both sets. */
- if (reg <= 32)
+ if (reg >= 0 && reg <= 32)
return reg;
/* fr4-fr31 are mapped from 72 in steps of 2. */
if (reg >= 72 && reg < 72 + 28 * 2 && !(reg & 1))
return HPPA64_FP4_REGNUM + (reg - 72) / 2;
- warning (_("Unmapped DWARF DBX Register #%d encountered."), reg);
return -1;
}
/* Stack base address at which the first parameter is stored. */
CORE_ADDR param_end = 0;
- /* The inner most end of the stack after all the parameters have
- been pushed. */
- CORE_ADDR new_sp = 0;
-
/* Two passes. First pass computes the location of everything,
second pass writes the bytes out. */
int write_pass;
}
case TYPE_CODE_PTR:
case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
return (TYPE_LENGTH (type) == 8);
default:
break;
while (regnum > HPPA_ARG0_REGNUM - 8 && len > 0)
{
regcache_cooked_write_part (regcache, regnum,
- offset % 8, min (len, 8), valbuf);
- offset += min (len, 8);
- valbuf += min (len, 8);
- len -= min (len, 8);
+ offset % 8, std::min (len, 8), valbuf);
+ offset += std::min (len, 8);
+ valbuf += std::min (len, 8);
+ len -= std::min (len, 8);
regnum--;
}
/* Allocate the outgoing parameter area. Make sure the outgoing
parameter area is multiple of 16 bytes in length. */
- sp += max (align_up (offset, 16), 64);
+ sp += std::max (align_up (offset, 16), (ULONGEST) 64);
/* Allocate 32-bytes of scratch space. The documentation doesn't
mention this, but it seems to be needed. */
while (len > 0)
{
regcache_cooked_read_part (regcache, regnum, offset,
- min (len, 8), readbuf);
- readbuf += min (len, 8);
- len -= min (len, 8);
+ std::min (len, 8), readbuf);
+ readbuf += std::min (len, 8);
+ len -= std::min (len, 8);
regnum++;
}
}
while (len > 0)
{
regcache_cooked_write_part (regcache, regnum, offset,
- min (len, 8), writebuf);
- writebuf += min (len, 8);
- len -= min (len, 8);
+ std::min (len, 8), writebuf);
+ writebuf += std::min (len, 8);
+ len -= std::min (len, 8);
regnum++;
}
}
}
CORE_ADDR
-hppa_read_pc (struct regcache *regcache)
+hppa_read_pc (readable_regcache *regcache)
{
ULONGEST ipsw;
ULONGEST pc;
- regcache_cooked_read_unsigned (regcache, HPPA_IPSW_REGNUM, &ipsw);
- regcache_cooked_read_unsigned (regcache, HPPA_PCOQ_HEAD_REGNUM, &pc);
+ regcache->cooked_read (HPPA_IPSW_REGNUM, &ipsw);
+ regcache->cooked_read (HPPA_PCOQ_HEAD_REGNUM, &pc);
/* If the current instruction is nullified, then we are effectively
still executing the previous instruction. Pretend we are still
/* std,ma X,D(sp) */
if ((inst & 0xffe00008) == 0x73c00008)
- return (inst & 0x1 ? -1 << 13 : 0) | (((inst >> 4) & 0x3ff) << 3);
+ return (inst & 0x1 ? -(1 << 13) : 0) | (((inst >> 4) & 0x3ff) << 3);
/* addil high21,%r30; ldo low11,(%r1),%r30)
save high bits in save_high21 for later use. */
}
/* Return the register number for a GR which is saved by INST or
- zero it INST does not save a GR. */
+ zero if INST does not save a GR.
-static int
-inst_saves_gr (unsigned long inst)
-{
- /* Does it look like a stw? */
- if ((inst >> 26) == 0x1a || (inst >> 26) == 0x1b
- || (inst >> 26) == 0x1f
- || ((inst >> 26) == 0x1f
- && ((inst >> 6) == 0xa)))
- return hppa_extract_5R_store (inst);
+ Referenced from:
- /* Does it look like a std? */
- if ((inst >> 26) == 0x1c
- || ((inst >> 26) == 0x03
- && ((inst >> 6) & 0xf) == 0xb))
- return hppa_extract_5R_store (inst);
+ parisc 1.1:
+ https://parisc.wiki.kernel.org/images-parisc/6/68/Pa11_acd.pdf
- /* Does it look like a stwm? GCC & HPC may use this in prologues. */
- if ((inst >> 26) == 0x1b)
- return hppa_extract_5R_store (inst);
+ parisc 2.0:
+ https://parisc.wiki.kernel.org/images-parisc/7/73/Parisc2.0.pdf
- /* Does it look like sth or stb? HPC versions 9.0 and later use these
- too. */
- if ((inst >> 26) == 0x19 || (inst >> 26) == 0x18
- || ((inst >> 26) == 0x3
- && (((inst >> 6) & 0xf) == 0x8
- || (inst >> 6) & 0xf) == 0x9))
- return hppa_extract_5R_store (inst);
+ According to Table 6-5 of Chapter 6 (Memory Reference Instructions)
+ on page 106 in parisc 2.0, all instructions for storing values from
+ the general registers are:
- return 0;
+ Store: stb, sth, stw, std (according to Chapter 7, they
+ are only in both "inst >> 26" and "inst >> 6".
+ Store Absolute: stwa, stda (according to Chapter 7, they are only
+ in "inst >> 6".
+ Store Bytes: stby, stdby (according to Chapter 7, they are
+ only in "inst >> 6").
+
+ For (inst >> 26), according to Chapter 7:
+
+ The effective memory reference address is formed by the addition
+ of an immediate displacement to a base value.
+
+ - stb: 0x18, store a byte from a general register.
+
+ - sth: 0x19, store a halfword from a general register.
+
+ - stw: 0x1a, store a word from a general register.
+
+ - stwm: 0x1b, store a word from a general register and perform base
+ register modification (2.0 will still treate it as stw).
+
+ - std: 0x1c, store a doubleword from a general register (2.0 only).
+
+ - stw: 0x1f, store a word from a general register (2.0 only).
+
+ For (inst >> 6) when ((inst >> 26) == 0x03), according to Chapter 7:
+
+ The effective memory reference address is formed by the addition
+ of an index value to a base value specified in the instruction.
+
+ - stb: 0x08, store a byte from a general register (1.1 calls stbs).
+
+ - sth: 0x09, store a halfword from a general register (1.1 calls
+ sths).
+
+ - stw: 0x0a, store a word from a general register (1.1 calls stws).
+
+ - std: 0x0b: store a doubleword from a general register (2.0 only)
+
+ Implement fast byte moves (stores) to unaligned word or doubleword
+ destination.
+
+ - stby: 0x0c, for unaligned word (1.1 calls stbys).
+
+ - stdby: 0x0d for unaligned doubleword (2.0 only).
+
+ Store a word or doubleword using an absolute memory address formed
+ using short or long displacement or indexed
+
+ - stwa: 0x0e, store a word from a general register to an absolute
+ address (1.0 calls stwas).
+
+ - stda: 0x0f, store a doubleword from a general register to an
+ absolute address (2.0 only). */
+
+static int
+inst_saves_gr (unsigned long inst)
+{
+ switch ((inst >> 26) & 0x0f)
+ {
+ case 0x03:
+ switch ((inst >> 6) & 0x0f)
+ {
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ return hppa_extract_5R_store (inst);
+ default:
+ return 0;
+ }
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ /* no 0x1d or 0x1e -- according to parisc 2.0 document */
+ case 0x1f:
+ return hppa_extract_5R_store (inst);
+ default:
+ return 0;
+ }
}
/* Return the register number for a FR which is saved by INST or
may be the first instruction of the prologue. If that happens, then
the instruction skipping code has a bug that needs to be fixed. */
if (post_prologue_pc != 0)
- return max (pc, post_prologue_pc);
+ return std::max (pc, post_prologue_pc);
else
return (skip_prologue_hard_way (gdbarch, pc, 1));
}
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, "base=%s (cached) }",
paddress (gdbarch, ((struct hppa_frame_cache *)*this_cache)->base));
- return (*this_cache);
+ return (struct hppa_frame_cache *) (*this_cache);
}
cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
(*this_cache) = cache;
{
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, "base=NULL (no unwind entry) }");
- return (*this_cache);
+ return (struct hppa_frame_cache *) (*this_cache);
}
/* Turn the Entry_GR field into a bitmask. */
{
error (_("Cannot read instruction at %s."),
paddress (gdbarch, pc));
- return (*this_cache);
+ return (struct hppa_frame_cache *) (*this_cache);
}
inst = extract_unsigned_integer (buf4, sizeof buf4, byte_order);
CORE_ADDR offset;
if ((inst >> 26) == 0x1c)
- offset = (inst & 0x1 ? -1 << 13 : 0)
+ offset = (inst & 0x1 ? -(1 << 13) : 0)
| (((inst >> 4) & 0x3ff) << 3);
else if ((inst >> 26) == 0x03)
offset = hppa_low_hppa_sign_extend (inst & 0x1f, 5);
if (hppa_debug)
fprintf_unfiltered (gdb_stdlog, "base=%s }",
paddress (gdbarch, ((struct hppa_frame_cache *)*this_cache)->base));
- return (*this_cache);
+ return (struct hppa_frame_cache *) (*this_cache);
}
static void
struct frame_id *this_id)
{
struct hppa_frame_cache *info;
- CORE_ADDR pc = get_frame_pc (this_frame);
struct unwind_table_entry *u;
info = hppa_frame_cache (this_frame, this_cache);
struct unwind_table_entry *u;
if (*this_cache)
- return *this_cache;
+ return (struct hppa_stub_unwind_cache *) *this_cache;
info = FRAME_OBSTACK_ZALLOC (struct hppa_stub_unwind_cache);
*this_cache = info;
info->base = get_frame_register_unsigned (this_frame, HPPA_SP_REGNUM);
- if (gdbarch_osabi (gdbarch) == GDB_OSABI_HPUX_SOM)
- {
- /* HPUX uses export stubs in function calls; the export stub clobbers
- the return value of the caller, and, later restores it from the
- stack. */
- u = find_unwind_entry (get_frame_pc (this_frame));
-
- if (u && u->stub_unwind.stub_type == EXPORT)
- {
- info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].addr = info->base - 24;
-
- return info;
- }
- }
-
/* By default we assume that stubs do not change the rp. */
info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].realreg = HPPA_RP_REGNUM;
/* Return the minimal symbol whose name is NAME and stub type is STUB_TYPE.
Return NULL if no such symbol was found. */
-struct minimal_symbol *
+struct bound_minimal_symbol
hppa_lookup_stub_minimal_symbol (const char *name,
enum unwind_stub_types stub_type)
{
struct objfile *objfile;
struct minimal_symbol *msym;
+ struct bound_minimal_symbol result = { NULL, NULL };
ALL_MSYMBOLS (objfile, msym)
{
u = find_unwind_entry (MSYMBOL_VALUE (msym));
if (u != NULL && u->stub_unwind.stub_type == stub_type)
- return msym;
+ {
+ result.objfile = objfile;
+ result.minsym = msym;
+ return result;
+ }
}
}
- return NULL;
+ return result;
}
static void
-unwind_command (char *exp, int from_tty)
+unwind_command (const char *exp, int from_tty)
{
CORE_ADDR address;
struct unwind_table_entry *u;
}
static enum register_status
-hppa_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
+hppa_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache,
int regnum, gdb_byte *buf)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
ULONGEST tmp;
enum register_status status;
- status = regcache_raw_read_unsigned (regcache, regnum, &tmp);
+ status = regcache->raw_read (regnum, &tmp);
if (status == REG_VALID)
{
if (regnum == HPPA_PCOQ_HEAD_REGNUM || regnum == HPPA_PCOQ_TAIL_REGNUM)
return frame_unwind_got_constant (this_frame, regnum, pc + 4);
}
- /* Make sure the "flags" register is zero in all unwound frames.
- The "flags" registers is a HP-UX specific wart, and only the code
- in hppa-hpux-tdep.c depends on it. However, it is easier to deal
- with it here. This shouldn't affect other systems since those
- should provide zero for the "flags" register anyway. */
- if (regnum == HPPA_FLAGS_REGNUM)
- return frame_unwind_got_constant (this_frame, regnum, 0);
-
return trad_frame_get_prev_register (this_frame, saved_regs, regnum);
}
\f
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
-
- /* Try to determine the ABI of the object we are loading. */
- if (info.abfd != NULL && info.osabi == GDB_OSABI_UNKNOWN)
- {
- /* If it's a SOM file, assume it's HP/UX SOM. */
- if (bfd_get_flavour (info.abfd) == bfd_target_som_flavour)
- info.osabi = GDB_OSABI_HPUX_SOM;
- }
/* find a candidate among the list of pre-declared architectures. */
arches = gdbarch_list_lookup_by_info (arches, &info);
/* The following gdbarch vector elements do not depend on the address
size, or in any other gdbarch element previously set. */
set_gdbarch_skip_prologue (gdbarch, hppa_skip_prologue);
- set_gdbarch_in_function_epilogue_p (gdbarch,
- hppa_in_function_epilogue_p);
+ set_gdbarch_stack_frame_destroyed_p (gdbarch,
+ hppa_stack_frame_destroyed_p);
set_gdbarch_inner_than (gdbarch, core_addr_greaterthan);
set_gdbarch_sp_regnum (gdbarch, HPPA_SP_REGNUM);
set_gdbarch_fp0_regnum (gdbarch, HPPA_FP0_REGNUM);
/* Helper for function argument information. */
set_gdbarch_fetch_pointer_argument (gdbarch, hppa_fetch_pointer_argument);
- set_gdbarch_print_insn (gdbarch, print_insn_hppa);
-
/* When a hardware watchpoint triggers, we'll move the inferior past
it by removing all eventpoints; stepping past the instruction
that caused the trigger; reinserting eventpoints; and checking
internal_error (__FILE__, __LINE__, _("bad switch"));
}
- set_gdbarch_breakpoint_from_pc (gdbarch, hppa_breakpoint_from_pc);
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch, hppa_breakpoint::kind_from_pc);
+ set_gdbarch_sw_breakpoint_from_kind (gdbarch, hppa_breakpoint::bp_from_kind);
set_gdbarch_pseudo_register_read (gdbarch, hppa_pseudo_register_read);
/* Frame unwind methods. */
fprintf_unfiltered (file, "elf = %s\n", tdep->is_elf ? "yes" : "no");
}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_hppa_tdep;
-
void
_initialize_hppa_tdep (void)
{
- struct cmd_list_element *c;
-
gdbarch_register (bfd_arch_hppa, hppa_gdbarch_init, hppa_dump_tdep);
hppa_objfile_priv_data = register_objfile_data ();