X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fhppa-linux-tdep.c;h=ff07b7d2d4c3e82d993a0f4c4c0af4d6487232af;hb=098caef485a4ece6096e6cdbb4cd9726e4a13386;hp=32c6068dbd9cd5d6737da407871715a83fbf47de;hpb=d49771efb59f489ecc7ece815583f57ffebbb523;p=binutils-gdb.git diff --git a/gdb/hppa-linux-tdep.c b/gdb/hppa-linux-tdep.c index 32c6068dbd9..ff07b7d2d4c 100644 --- a/gdb/hppa-linux-tdep.c +++ b/gdb/hppa-linux-tdep.c @@ -1,22 +1,21 @@ -/* Target-dependent code for Linux running on PA-RISC, for GDB. +/* Target-dependent code for GNU/Linux running on PA-RISC, for GDB. - Copyright 2004 Free Software Foundation, Inc. + Copyright (C) 2004-2021 Free Software Foundation, Inc. -This file is part of GDB. + This file is part of GDB. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ #include "defs.h" #include "gdbcore.h" @@ -27,37 +26,36 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "glibc-tdep.h" #include "frame-unwind.h" #include "trad-frame.h" -#include "dwarf2-frame.h" +#include "dwarf2/frame.h" #include "value.h" +#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 >= 0 && 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\n", reg); return -1; } -#endif static void -hppa_linux_target_write_pc (CORE_ADDR v, ptid_t ptid) +hppa_linux_target_write_pc (struct regcache *regcache, CORE_ADDR v) { /* Probably this should be done by the kernel, but it isn't. */ - write_register_pid (HPPA_PCOQ_HEAD_REGNUM, v | 0x3, ptid); - write_register_pid (HPPA_PCOQ_TAIL_REGNUM, (v + 4) | 0x3, ptid); + regcache_cooked_write_unsigned (regcache, HPPA_PCOQ_HEAD_REGNUM, v | 0x3); + regcache_cooked_write_unsigned (regcache, + HPPA_PCOQ_TAIL_REGNUM, (v + 4) | 0x3); } /* An instruction to match. */ @@ -67,57 +65,6 @@ struct insn_pattern unsigned int mask; /* ... with this mask. */ }; -/* See bfd/elf32-hppa.c */ -static struct insn_pattern hppa_long_branch_stub[] = { - /* ldil LR'xxx,%r1 */ - { 0x20200000, 0xffe00000 }, - /* be,n RR'xxx(%sr4,%r1) */ - { 0xe0202002, 0xffe02002 }, - { 0, 0 } -}; - -static struct insn_pattern hppa_long_branch_pic_stub[] = { - /* b,l .+8, %r1 */ - { 0xe8200000, 0xffe00000 }, - /* addil LR'xxx - ($PIC_pcrel$0 - 4), %r1 */ - { 0x28200000, 0xffe00000 }, - /* be,n RR'xxxx - ($PIC_pcrel$0 - 8)(%sr4, %r1) */ - { 0xe0202002, 0xffe02002 }, - { 0, 0 } -}; - -static struct insn_pattern hppa_import_stub[] = { - /* addil LR'xxx, %dp */ - { 0x2b600000, 0xffe00000 }, - /* ldw RR'xxx(%r1), %r21 */ - { 0x48350000, 0xffffb000 }, - /* bv %r0(%r21) */ - { 0xeaa0c000, 0xffffffff }, - /* ldw RR'xxx+4(%r1), %r19 */ - { 0x48330000, 0xffffb000 }, - { 0, 0 } -}; - -static struct insn_pattern hppa_import_pic_stub[] = { - /* addil LR'xxx,%r19 */ - { 0x2a600000, 0xffe00000 }, - /* ldw RR'xxx(%r1),%r21 */ - { 0x48350000, 0xffffb000 }, - /* bv %r0(%r21) */ - { 0xeaa0c000, 0xffffffff }, - /* ldw RR'xxx+4(%r1),%r19 */ - { 0x48330000, 0xffffb000 }, - { 0, 0 }, -}; - -static struct insn_pattern hppa_plt_stub[] = { - /* b,l 1b, %r20 - 1b is 3 insns before here */ - { 0xea9f1fdd, 0xffffffff }, - /* depi 0,31,2,%r20 */ - { 0xd6801c1e, 0xffffffff }, - { 0, 0 } -}; - static struct insn_pattern hppa_sigtramp[] = { /* ldi 0, %r25 or ldi 1, %r25 */ { 0x34190000, 0xfffffffd }, @@ -140,132 +87,28 @@ static struct insn_pattern hppa_sigtramp[] = { When the match is successful, fill INSN[i] with what PATTERN[i] matched. */ static int -insns_match_pattern (CORE_ADDR pc, - struct insn_pattern *pattern, - unsigned int *insn) +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; + npc += 4; else - return 0; + return 0; } return 1; } -static int -hppa_linux_in_dyncall (CORE_ADDR pc) -{ - static CORE_ADDR dyncall = 0; - - /* FIXME: if we switch exec files, dyncall should be reinitialized */ - if (!dyncall) - { - struct minimal_symbol *minsym; - - minsym = lookup_minimal_symbol ("$$dyncall", NULL, NULL); - if (minsym) - dyncall = SYMBOL_VALUE_ADDRESS (minsym); - else - dyncall = -1; - } - - return pc == dyncall; -} - -/* There are several kinds of "trampolines" that we need to deal with: - - long branch stubs: these are inserted by the linker when a branch - target is too far away for a branch insn to reach - - plt stubs: these should go into the .plt section, so are easy to find - - import stubs: used to call from object to shared lib or shared lib to - shared lib; these go in regular text sections. In fact the linker tries - to put them throughout the code because branches have limited reachability. - We use the same mechanism as ppc64 to recognize the stub insn patterns. - - $$dyncall: similar to hpux, hppa-linux uses $$dyncall for indirect function - calls. $$dyncall is exported by libgcc.a */ -static int -hppa_linux_in_solib_call_trampoline (CORE_ADDR pc, char *name) -{ - unsigned int insn[HPPA_MAX_INSN_PATTERN_LEN]; - int r; - - r = in_plt_section (pc, name) - || hppa_linux_in_dyncall (pc) - || insns_match_pattern (pc, hppa_import_stub, insn) - || insns_match_pattern (pc, hppa_import_pic_stub, insn) - || insns_match_pattern (pc, hppa_long_branch_stub, insn) - || insns_match_pattern (pc, hppa_long_branch_pic_stub, insn); - - return r; -} - -static CORE_ADDR -hppa_linux_skip_trampoline_code (CORE_ADDR pc) -{ - unsigned int insn[HPPA_MAX_INSN_PATTERN_LEN]; - int dp_rel, pic_rel; - - /* dyncall handles both PLABELs and direct addresses */ - if (hppa_linux_in_dyncall (pc)) - { - pc = (CORE_ADDR) read_register (22); - - /* PLABELs have bit 30 set; if it's a PLABEL, then dereference it */ - if (pc & 0x2) - pc = (CORE_ADDR) read_memory_integer (pc & ~0x3, TARGET_PTR_BIT / 8); - - return pc; - } - - dp_rel = pic_rel = 0; - if ((dp_rel = insns_match_pattern (pc, hppa_import_stub, insn)) - || (pic_rel = insns_match_pattern (pc, hppa_import_pic_stub, insn))) - { - /* Extract the target address from the addil/ldw sequence. */ - pc = hppa_extract_21 (insn[0]) + hppa_extract_14 (insn[1]); - - if (dp_rel) - pc += (CORE_ADDR) read_register (27); - else - pc += (CORE_ADDR) read_register (19); - - /* fallthrough */ - } - - if (in_plt_section (pc, NULL)) - { - pc = (CORE_ADDR) read_memory_integer (pc, TARGET_PTR_BIT / 8); - - /* if the plt slot has not yet been resolved, the target will - be the plt stub */ - if (in_plt_section (pc, NULL)) - { - /* Sanity check: are we pointing to the plt stub? */ - if (insns_match_pattern (pc, hppa_plt_stub, insn)) - { - /* this should point to the fixup routine */ - pc = (CORE_ADDR) read_memory_integer (pc + 8, TARGET_PTR_BIT / 8); - } - else - { - error ("Cannot resolve plt stub at 0x%s\n", - paddr_nz (pc)); - pc = 0; - } - } - } - - return pc; -} - /* Signal frames. */ /* (This is derived from MD_FALLBACK_FRAME_STATE_FOR in gcc.) @@ -288,11 +131,11 @@ hppa_linux_skip_trampoline_code (CORE_ADDR pc) 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; - int try; + int attempt; /* offsets to try to find the trampoline */ static int pcoffs[] = { 0, 4*4, 5*4 }; /* offsets to the rt_sigframe structure */ @@ -310,64 +153,65 @@ hppa_linux_sigtramp_find_sigcontext (CORE_ADDR pc) e4008200 be,l 0x100(%sr2, %r0), %sr0, %r31 08000240 nop */ - for (try = 0; try < ARRAY_SIZE (pcoffs); try++) + for (attempt = 0; attempt < ARRAY_SIZE (pcoffs); attempt++) { - if (insns_match_pattern (sp + pcoffs[try], hppa_sigtramp, dummy)) + if (insns_match_pattern (gdbarch, sp + pcoffs[attempt], + hppa_sigtramp, dummy)) { - offs = sfoffs[try]; + offs = sfoffs[attempt]; 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]; + attempt = 2; + sp = pc - pcoffs[attempt]; } else { - return 0; + return 0; } } /* 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; + return sp + sfoffs[attempt] + 128 + 24; } struct hppa_linux_sigtramp_unwind_cache { CORE_ADDR base; - struct trad_frame_saved_reg *saved_regs; + trad_frame_saved_reg *saved_regs; }; 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; if (*this_cache) - return *this_cache; + return (struct hppa_linux_sigtramp_unwind_cache *) *this_cache; 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: @@ -382,17 +226,18 @@ hppa_linux_sigtramp_frame_unwind_cache (struct frame_info *next_frame, /* 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].set_addr (scptr); scptr += 4; /* General registers. */ for (i = 1; i < 32; i++) { - info->saved_regs[HPPA_R0_REGNUM + i].addr = scptr; + info->saved_regs[HPPA_R0_REGNUM + i].set_addr (scptr); scptr += 4; } - /* Pad. */ + /* Pad to long long boundary. */ scptr += 4; /* FP regs; FP0-3 are not restored. */ @@ -400,75 +245,80 @@ hppa_linux_sigtramp_frame_unwind_cache (struct frame_info *next_frame, for (i = 4; i < 32; i++) { - info->saved_regs[HPPA_FP0_REGNUM + (i * 2)].addr = scptr; + info->saved_regs[HPPA_FP0_REGNUM + (i * 2)].set_addr (scptr); scptr += 4; - info->saved_regs[HPPA_FP0_REGNUM + (i * 2) + 1].addr = scptr; + info->saved_regs[HPPA_FP0_REGNUM + (i * 2) + 1].set_addr (scptr); scptr += 4; } - /* IASQ/IAOQ. */ - info->saved_regs[HPPA_PCSQ_HEAD_REGNUM].addr = scptr; + /* IASQ/IAOQ. */ + info->saved_regs[HPPA_PCSQ_HEAD_REGNUM].set_addr (scptr); scptr += 4; - info->saved_regs[HPPA_PCSQ_TAIL_REGNUM].addr = scptr; + info->saved_regs[HPPA_PCSQ_TAIL_REGNUM].set_addr (scptr); scptr += 4; - info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].addr = scptr; + info->saved_regs[HPPA_PCOQ_HEAD_REGNUM].set_addr (scptr); scptr += 4; - info->saved_regs[HPPA_PCOQ_TAIL_REGNUM].addr = scptr; + info->saved_regs[HPPA_PCOQ_TAIL_REGNUM].set_addr (scptr); scptr += 4; - info->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM); + info->saved_regs[HPPA_SAR_REGNUM].set_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, void *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. @@ -480,8 +330,10 @@ hppa_linux_sigtramp_unwind_sniffer (struct frame_info *next_frame) d_un.d_ptr value is the global pointer. */ static CORE_ADDR -hppa_linux_find_global_pointer (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; @@ -491,19 +343,19 @@ hppa_linux_find_global_pointer (struct value *function) 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); @@ -519,19 +371,21 @@ hppa_linux_find_global_pointer (struct value *function) if (osect < faddr_sect->objfile->sections_end) { - CORE_ADDR addr; + CORE_ADDR addr, endaddr; - addr = osect->addr; - while (addr < osect->endaddr) + addr = obj_section_addr (osect); + endaddr = obj_section_endaddr (osect); + + 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) { @@ -540,9 +394,9 @@ hppa_linux_find_global_pointer (struct value *function) 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; } @@ -555,32 +409,103 @@ hppa_linux_find_global_pointer (struct value *function) } return 0; } + +/* + * Registers saved in a coredump: + * gr0..gr31 + * sr0..sr7 + * iaoq0..iaoq1 + * iasq0..iasq1 + * sar, iir, isr, ior, ipsw + * cr0, cr24..cr31 + * cr8,9,12,13 + * cr10, cr15 + */ + +static const struct regcache_map_entry hppa_linux_gregmap[] = + { + { 32, HPPA_R0_REGNUM }, + { 1, HPPA_SR4_REGNUM+1 }, + { 1, HPPA_SR4_REGNUM+2 }, + { 1, HPPA_SR4_REGNUM+3 }, + { 1, HPPA_SR4_REGNUM+4 }, + { 1, HPPA_SR4_REGNUM }, + { 1, HPPA_SR4_REGNUM+5 }, + { 1, HPPA_SR4_REGNUM+6 }, + { 1, HPPA_SR4_REGNUM+7 }, + { 1, HPPA_PCOQ_HEAD_REGNUM }, + { 1, HPPA_PCOQ_TAIL_REGNUM }, + { 1, HPPA_PCSQ_HEAD_REGNUM }, + { 1, HPPA_PCSQ_TAIL_REGNUM }, + { 1, HPPA_SAR_REGNUM }, + { 1, HPPA_IIR_REGNUM }, + { 1, HPPA_ISR_REGNUM }, + { 1, HPPA_IOR_REGNUM }, + { 1, HPPA_IPSW_REGNUM }, + { 1, HPPA_RCR_REGNUM }, + { 8, HPPA_TR0_REGNUM }, + { 4, HPPA_PID0_REGNUM }, + { 1, HPPA_CCR_REGNUM }, + { 1, HPPA_EIEM_REGNUM }, + { 0 } + }; + +static const struct regcache_map_entry hppa_linux_fpregmap[] = + { + /* FIXME: Only works for 32-bit mode. In 64-bit mode there should + be 32 fpregs, 8 bytes each. */ + { 64, HPPA_FP0_REGNUM, 4 }, + { 0 } + }; + +/* HPPA Linux kernel register set. */ +static const struct regset hppa_linux_regset = +{ + hppa_linux_gregmap, + regcache_supply_regset, regcache_collect_regset +}; -/* Forward declarations. */ -extern initialize_file_ftype _initialize_hppa_linux_tdep; +static const struct regset hppa_linux_fpregset = +{ + hppa_linux_fpregmap, + regcache_supply_regset, regcache_collect_regset +}; + +static void +hppa_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, + iterate_over_regset_sections_cb *cb, + void *cb_data, + const struct regcache *regcache) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + cb (".reg", 80 * tdep->bytes_per_address, 80 * tdep->bytes_per_address, + &hppa_linux_regset, NULL, cb_data); + cb (".reg2", 64 * 4, 64 * 4, &hppa_linux_fpregset, NULL, cb_data); +} static void hppa_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - /* Linux is always ELF. */ + linux_init_abi (info, gdbarch, 0); + + /* GNU/Linux is always ELF. */ tdep->is_elf = 1; tdep->find_global_pointer = hppa_linux_find_global_pointer; 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 (gdbarch, svr4_ilp32_fetch_link_map_offsets); - set_gdbarch_in_solib_call_trampoline - (gdbarch, hppa_linux_in_solib_call_trampoline); - set_gdbarch_skip_trampoline_code - (gdbarch, hppa_linux_skip_trampoline_code); + tdep->in_solib_call_trampoline = hppa_in_solib_call_trampoline; + set_gdbarch_skip_trampoline_code (gdbarch, hppa_skip_trampoline_code); /* GNU/Linux uses the dynamic linker included in the GNU C Library. */ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); @@ -589,18 +514,24 @@ hppa_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) some discussions to support 128-bit long double, but it requires some more work in gcc and glibc first. */ set_gdbarch_long_double_bit (gdbarch, 64); + set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double); + + set_gdbarch_iterate_over_regset_sections + (gdbarch, hppa_linux_iterate_over_regset_sections); -#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, + svr4_fetch_objfile_link_map); } +void _initialize_hppa_linux_tdep (); void -_initialize_hppa_linux_tdep (void) +_initialize_hppa_linux_tdep () { - gdbarch_register_osabi (bfd_arch_hppa, 0, 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); }