/* Target-dependent code for GNU/Linux running on PA-RISC, for GDB.
- Copyright (C) 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2004-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "regset.h"
#include "regcache.h"
#include "hppa-tdep.h"
-
+#include "linux-tdep.h"
#include "elf/common.h"
-#if 0
-/* Convert DWARF register number REG to the appropriate register
- number used by GDB. */
+/* Map DWARF DBX register numbers to GDB register numbers. */
static int
-hppa_dwarf_reg_to_regnum (int reg)
+hppa_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
- /* registers 0 - 31 are the same in both sets */
- if (reg < 32)
+ /* The general registers and the sar are the same in both sets. */
+ if (reg <= 32)
return reg;
- /* dwarf regs 32 to 85 are fpregs 4 - 31 */
- if (reg >= 32 && reg <= 85)
- return HPPA_FP4_REGNUM + (reg - 32);
+ /* fr4-fr31 (left and right halves) are mapped from 72. */
+ if (reg >= 72 && reg <= 72 + 28 * 2)
+ return HPPA_FP4_REGNUM + (reg - 72);
- warning (_("Unmapped DWARF Register #%d encountered."), reg);
+ warning (_("Unmapped DWARF DBX Register #%d encountered."), reg);
return -1;
}
-#endif
static void
hppa_linux_target_write_pc (struct regcache *regcache, CORE_ADDR v)
{
/* Probably this should be done by the kernel, but it isn't. */
regcache_cooked_write_unsigned (regcache, HPPA_PCOQ_HEAD_REGNUM, v | 0x3);
- regcache_cooked_write_unsigned (regcache, HPPA_PCOQ_TAIL_REGNUM, (v + 4) | 0x3);
+ regcache_cooked_write_unsigned (regcache,
+ HPPA_PCOQ_TAIL_REGNUM, (v + 4) | 0x3);
}
/* An instruction to match. */
When the match is successful, fill INSN[i] with what PATTERN[i]
matched. */
static int
-insns_match_pattern (CORE_ADDR pc,
+insns_match_pattern (struct gdbarch *gdbarch, CORE_ADDR pc,
struct insn_pattern *pattern,
unsigned int *insn)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int i;
CORE_ADDR npc = pc;
for (i = 0; pattern[i].mask; i++)
{
- char buf[4];
+ gdb_byte buf[4];
- read_memory_nobpt (npc, buf, 4);
- insn[i] = extract_unsigned_integer (buf, 4);
+ target_read_memory (npc, buf, 4);
+ insn[i] = extract_unsigned_integer (buf, 4, byte_order);
if ((insn[i] & pattern[i].mask) == pattern[i].data)
npc += 4;
else
Note that with a 2.4 64-bit kernel, the signal context is not properly
passed back to userspace so the unwind will not work correctly. */
static CORE_ADDR
-hppa_linux_sigtramp_find_sigcontext (CORE_ADDR pc)
+hppa_linux_sigtramp_find_sigcontext (struct gdbarch *gdbarch, CORE_ADDR pc)
{
unsigned int dummy[HPPA_MAX_INSN_PATTERN_LEN];
int offs = 0;
for (try = 0; try < ARRAY_SIZE (pcoffs); try++)
{
- if (insns_match_pattern (sp + pcoffs[try], hppa_sigtramp, dummy))
+ if (insns_match_pattern (gdbarch, sp + pcoffs[try],
+ hppa_sigtramp, dummy))
{
offs = sfoffs[try];
break;
if (offs == 0)
{
- if (insns_match_pattern (pc, hppa_sigtramp, dummy))
+ if (insns_match_pattern (gdbarch, pc, hppa_sigtramp, dummy))
{
/* sigaltstack case: we have no way of knowing which offset to
- use in this case; default to new kernel handling. If this is
+ use in this case; default to new kernel handling. If this is
wrong the unwinding will fail. */
try = 2;
sp = pc - pcoffs[try];
/* sp + sfoffs[try] points to a struct rt_sigframe, which contains
a struct siginfo and a struct ucontext. struct ucontext contains
- a struct sigcontext. Return an offset to this sigcontext here. Too
- bad we cannot include system specific headers :-(.
+ a struct sigcontext. Return an offset to this sigcontext here. Too
+ bad we cannot include system specific headers :-(.
sizeof(struct siginfo) == 128
offsetof(struct ucontext, uc_mcontext) == 24. */
return sp + sfoffs[try] + 128 + 24;
};
static struct hppa_linux_sigtramp_unwind_cache *
-hppa_linux_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
+hppa_linux_sigtramp_frame_unwind_cache (struct frame_info *this_frame,
void **this_cache)
{
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct hppa_linux_sigtramp_unwind_cache *info;
CORE_ADDR pc, scptr;
int i;
info = FRAME_OBSTACK_ZALLOC (struct hppa_linux_sigtramp_unwind_cache);
*this_cache = info;
- info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+ info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
- pc = frame_pc_unwind (next_frame);
- scptr = hppa_linux_sigtramp_find_sigcontext (pc);
+ pc = get_frame_pc (this_frame);
+ scptr = hppa_linux_sigtramp_find_sigcontext (gdbarch, pc);
/* structure of struct sigcontext:
/* Skip sc_flags. */
scptr += 4;
- /* GR[0] is the psw, we don't restore that. */
+ /* GR[0] is the psw. */
+ info->saved_regs[HPPA_IPSW_REGNUM].addr = scptr;
scptr += 4;
/* General registers. */
scptr += 4;
}
- /* Pad. */
+ /* Pad to long long boundary. */
scptr += 4;
/* FP regs; FP0-3 are not restored. */
scptr += 4;
}
- /* IASQ/IAOQ. */
+ /* IASQ/IAOQ. */
info->saved_regs[HPPA_PCSQ_HEAD_REGNUM].addr = scptr;
scptr += 4;
info->saved_regs[HPPA_PCSQ_TAIL_REGNUM].addr = scptr;
info->saved_regs[HPPA_PCOQ_TAIL_REGNUM].addr = scptr;
scptr += 4;
- info->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+ info->saved_regs[HPPA_SAR_REGNUM].addr = scptr;
+
+ info->base = get_frame_register_unsigned (this_frame, HPPA_SP_REGNUM);
return info;
}
static void
-hppa_linux_sigtramp_frame_this_id (struct frame_info *next_frame,
+hppa_linux_sigtramp_frame_this_id (struct frame_info *this_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
struct hppa_linux_sigtramp_unwind_cache *info
- = hppa_linux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
- *this_id = frame_id_build (info->base, frame_pc_unwind (next_frame));
+ = hppa_linux_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache);
+ *this_id = frame_id_build (info->base, get_frame_pc (this_frame));
}
-static void
-hppa_linux_sigtramp_frame_prev_register (struct frame_info *next_frame,
+static struct value *
+hppa_linux_sigtramp_frame_prev_register (struct frame_info *this_frame,
void **this_prologue_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp,
- CORE_ADDR *addrp,
- int *realnump, gdb_byte *valuep)
+ int regnum)
{
struct hppa_linux_sigtramp_unwind_cache *info
- = hppa_linux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
- hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ = hppa_linux_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache);
+ return hppa_frame_prev_register_helper (this_frame,
+ info->saved_regs, regnum);
}
-static const struct frame_unwind hppa_linux_sigtramp_frame_unwind = {
- SIGTRAMP_FRAME,
- hppa_linux_sigtramp_frame_this_id,
- hppa_linux_sigtramp_frame_prev_register
-};
-
/* hppa-linux always uses "new-style" rt-signals. The signal handler's return
address should point to a signal trampoline on the stack. The signal
trampoline is embedded in a rt_sigframe structure that is aligned on
the stack. We take advantage of the fact that sp must be 64-byte aligned,
and the trampoline is small, so by rounding down the trampoline address
we can find the beginning of the struct rt_sigframe. */
-static const struct frame_unwind *
-hppa_linux_sigtramp_unwind_sniffer (struct frame_info *next_frame)
+static int
+hppa_linux_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
{
- CORE_ADDR pc = frame_pc_unwind (next_frame);
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ CORE_ADDR pc = get_frame_pc (this_frame);
- if (hppa_linux_sigtramp_find_sigcontext (pc))
- return &hppa_linux_sigtramp_frame_unwind;
+ if (hppa_linux_sigtramp_find_sigcontext (gdbarch, pc))
+ return 1;
- return NULL;
+ return 0;
}
+static const struct frame_unwind hppa_linux_sigtramp_frame_unwind = {
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ hppa_linux_sigtramp_frame_this_id,
+ hppa_linux_sigtramp_frame_prev_register,
+ NULL,
+ hppa_linux_sigtramp_frame_sniffer
+};
+
/* Attempt to find (and return) the global pointer for the given
function.
d_un.d_ptr value is the global pointer. */
static CORE_ADDR
-hppa_linux_find_global_pointer (struct gdbarch *gdbarch, struct value *function)
+hppa_linux_find_global_pointer (struct gdbarch *gdbarch,
+ struct value *function)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct obj_section *faddr_sect;
CORE_ADDR faddr;
if (faddr & 2)
{
int status;
- char buf[4];
+ gdb_byte buf[4];
faddr &= ~3;
status = target_read_memory (faddr + 4, buf, sizeof (buf));
if (status == 0)
- return extract_unsigned_integer (buf, sizeof (buf));
+ return extract_unsigned_integer (buf, sizeof (buf), byte_order);
}
/* If the address is in the plt section, then the real function hasn't
yet been fixed up by the linker so we cannot determine the gp of
that function. */
- if (in_plt_section (faddr, NULL))
+ if (in_plt_section (faddr))
return 0;
faddr_sect = find_pc_section (faddr);
if (osect < faddr_sect->objfile->sections_end)
{
- CORE_ADDR addr;
+ CORE_ADDR addr, endaddr;
+
+ addr = obj_section_addr (osect);
+ endaddr = obj_section_endaddr (osect);
- addr = osect->addr;
- while (addr < osect->endaddr)
+ while (addr < endaddr)
{
int status;
LONGEST tag;
- char buf[4];
+ gdb_byte buf[4];
status = target_read_memory (addr, buf, sizeof (buf));
if (status != 0)
break;
- tag = extract_signed_integer (buf, sizeof (buf));
+ tag = extract_signed_integer (buf, sizeof (buf), byte_order);
if (tag == DT_PLTGOT)
{
status = target_read_memory (addr + 4, buf, sizeof (buf));
if (status != 0)
break;
- global_pointer = extract_unsigned_integer (buf, sizeof (buf));
-
- /* The payoff... */
+ global_pointer = extract_unsigned_integer (buf, sizeof (buf),
+ byte_order);
+ /* The payoff... */
return global_pointer;
}
int i, offset;
offset = 0;
- for (i = 0; i < 31; i++)
+ for (i = 0; i < 64; i++)
{
if (regnum == HPPA_FP0_REGNUM + i || regnum == -1)
regcache_raw_supply (regcache, HPPA_FP0_REGNUM + i,
buf + offset);
- offset += 8;
+ offset += 4;
}
}
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ linux_init_abi (info, gdbarch);
+
/* GNU/Linux is always ELF. */
tdep->is_elf = 1;
set_gdbarch_write_pc (gdbarch, hppa_linux_target_write_pc);
- frame_unwind_append_sniffer (gdbarch, hppa_linux_sigtramp_unwind_sniffer);
+ frame_unwind_append_unwinder (gdbarch, &hppa_linux_sigtramp_frame_unwind);
/* GNU/Linux uses SVR4-style shared libraries. */
set_solib_svr4_fetch_link_map_offsets
set_gdbarch_regset_from_core_section
(gdbarch, hppa_linux_regset_from_core_section);
-#if 0
- /* Dwarf-2 unwinding support. Not yet working. */
- set_gdbarch_dwarf_reg_to_regnum (gdbarch, hppa_dwarf_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, hppa_dwarf_reg_to_regnum);
- frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
- frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
-#endif
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
void
_initialize_hppa_linux_tdep (void)
{
- gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_LINUX, hppa_linux_init_abi);
- gdbarch_register_osabi (bfd_arch_hppa, bfd_mach_hppa20w, GDB_OSABI_LINUX, hppa_linux_init_abi);
+ gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_LINUX,
+ hppa_linux_init_abi);
+ gdbarch_register_osabi (bfd_arch_hppa, bfd_mach_hppa20w,
+ GDB_OSABI_LINUX, hppa_linux_init_abi);
}