/* Target-dependent code for the HP PA-RISC architecture.
- Copyright (C) 1986-2013 Free Software Foundation, Inc.
+ Copyright (C) 1986-2016 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 SYMBOL_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;
unsigned int inst;
- char buf[4];
+ gdb_byte buf[4];
status = target_read_memory (pc, buf, 4);
if (status != 0)
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. */
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;
struct type *type = check_typedef (value_type (arg));
/* The corresponding parameter that is pushed onto the
stack, and [possibly] passed in a register. */
- char param_val[8];
+ gdb_byte param_val[8];
int param_len;
memset (param_val, 0, sizeof param_val);
if (TYPE_LENGTH (type) > 8)
addr += 2 * 8)
{
ULONGEST opdaddr;
- char tmp[8];
+ gdb_byte tmp[8];
if (target_read_memory (addr, tmp, sizeof (tmp)))
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++;
}
}
/* 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
int stop_before_branch)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- char buf[4];
+ gdb_byte buf[4];
CORE_ADDR orig_pc = pc;
unsigned long inst, stack_remaining, save_gr, save_fr, save_rp, save_sp;
unsigned long args_stored, status, i, restart_gr, restart_fr;
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. */
pc += 4)
{
int reg;
- char buf4[4];
+ gdb_byte buf4[4];
long inst;
if (!safe_frame_unwind_memory (this_frame, pc, buf4, sizeof buf4))
{
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;
if (pc == 0
|| (tdep->in_solib_call_trampoline != NULL
- && tdep->in_solib_call_trampoline (gdbarch, pc, NULL))
+ && tdep->in_solib_call_trampoline (gdbarch, pc))
|| gdbarch_in_solib_return_trampoline (gdbarch, pc, NULL))
return 1;
return 0;
/* 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)
{
- if (strcmp (SYMBOL_LINKAGE_NAME (msym), name) == 0)
+ if (strcmp (MSYMBOL_LINKAGE_NAME (msym), name) == 0)
{
struct unwind_table_entry *u;
- u = find_unwind_entry (SYMBOL_VALUE (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
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
{ 0, 0 }
};
-static struct insn_pattern hppa_sigtramp[] = {
- /* ldi 0, %r25 or ldi 1, %r25 */
- { 0x34190000, 0xfffffffd },
- /* ldi __NR_rt_sigreturn, %r20 */
- { 0x3414015a, 0xffffffff },
- /* be,l 0x100(%sr2, %r0), %sr0, %r31 */
- { 0xe4008200, 0xffffffff },
- /* nop */
- { 0x08000240, 0xffffffff },
- { 0, 0 }
-};
-
/* Maximum number of instructions on the patterns above. */
#define HPPA_MAX_INSN_PATTERN_LEN 4
}
int
-hppa_in_solib_call_trampoline (struct gdbarch *gdbarch,
- CORE_ADDR pc, char *name)
+hppa_in_solib_call_trampoline (struct gdbarch *gdbarch, CORE_ADDR pc)
{
unsigned int insn[HPPA_MAX_INSN_PATTERN_LEN];
struct unwind_table_entry *u;
- if (in_plt_section (pc, name) || hppa_in_dyncall (pc))
+ if (in_plt_section (pc) || hppa_in_dyncall (pc))
return 1;
/* The GNU toolchain produces linker stubs without unwind
/* fallthrough */
}
- if (in_plt_section (pc, NULL))
+ if (in_plt_section (pc))
{
pc = read_memory_typed_address (pc, func_ptr_type);
/* If the PLT slot has not yet been resolved, the target will be
the PLT stub. */
- if (in_plt_section (pc, NULL))
+ if (in_plt_section (pc))
{
/* Sanity check: are we pointing to the PLT stub? */
if (!hppa_match_insns (gdbarch, pc, hppa_plt_stub, insn))
return (arches->gdbarch);
/* If none found, then allocate and initialize one. */
- tdep = XZALLOC (struct gdbarch_tdep);
+ tdep = XCNEW (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
/* Determine from the bfd_arch_info structure if we are dealing with
/* 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);
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. */
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 ();