From 60ac68f601885ea6480229a5c8a89a0257da376c Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Mon, 2 Mar 2015 02:31:12 +0000 Subject: [PATCH 05/10] Add support for Renesas SH (sh4) architecture. gdb (7.4-1~cvs20111117.2) experimental; urgency=low . * Add Renesas SH (sh4) support (Closes: #576242) - Thanks Nobuhiro Iwamatsu, Takashi Yoshii. Author: Hector Oron Bug-Debian: http://bugs.debian.org/576242 Upstream-Status: Pending Signed-off-by: Khem Raj --- gdb/Makefile.in | 2 + gdb/configure.host | 1 + gdb/sh-linux-tdep.c | 519 +++++++++++++++++++++++++++++++++++ gdb/sh-tdep.c | 54 ++-- gdb/sh-tdep.h | 49 ++++ gdb/testsuite/gdb.asm/asm-source.exp | 5 + gdb/testsuite/gdb.asm/sh.inc | 3 +- gdb/testsuite/gdb.base/annota1.c | 3 + gdb/testsuite/gdb.base/annota3.c | 4 + gdb/testsuite/gdb.base/sigall.c | 3 + gdb/testsuite/gdb.base/signals.c | 4 + 11 files changed, 618 insertions(+), 29 deletions(-) diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 8be73ba423..e287ff6a2e 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2638,6 +2638,8 @@ ALLDEPFILES = \ sh-nbsd-tdep.c \ sh-tdep.c \ sh64-tdep.c \ + sh-linux-tdep.c \ + sh-linux-nat.c \ sol2-tdep.c \ solib-aix.c \ solib-spu.c \ diff --git a/gdb/configure.host b/gdb/configure.host index d74fd04934..be12de1446 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -150,6 +150,7 @@ powerpc*-*-linux*) gdb_host=linux ;; s390*-*-linux*) gdb_host=linux ;; +sh*-*-linux*) gdb_host=linux ;; sh*-*-netbsdelf* | sh*-*-knetbsd*-gnu) gdb_host=nbsd ;; sh*-*-openbsd*) gdb_host=nbsd ;; diff --git a/gdb/sh-linux-tdep.c b/gdb/sh-linux-tdep.c index c5c745d218..84e539aad3 100644 --- a/gdb/sh-linux-tdep.c +++ b/gdb/sh-linux-tdep.c @@ -18,14 +18,37 @@ along with this program. If not, see . */ #include "defs.h" +#include "gdbcore.h" +#include "frame.h" +#include "frame-base.h" +#include "frame-unwind.h" +#include "dwarf2-frame.h" +#include "value.h" +#include "regcache.h" +#include "inferior.h" #include "osabi.h" +#include "reggroups.h" +#include "arch-utils.h" +#include "floatformat.h" #include "solib-svr4.h" #include "symtab.h" +#include "gdb_string.h" +#include "command.h" +#include "gdb_assert.h" #include "trad-frame.h" #include "tramp-frame.h" +#include +#include +#include +#include +#include + +#include + +#include "regset.h" #include "glibc-tdep.h" #include "sh-tdep.h" #include "linux-tdep.h" @@ -180,9 +203,505 @@ static struct tramp_frame sh_linux_rt_sigreturn_tramp_frame = { sh_linux_rt_sigreturn_init }; +/* Recognizing signal handler frames. */ + +/* GNU/Linux has two flavors of signals. Normal signal handlers, and + "realtime" (RT) signals. The RT signals can provide additional + information to the signal handler if the SA_SIGINFO flag is set + when establishing a signal handler using `sigaction'. It is not + unlikely that future versions of GNU/Linux will support SA_SIGINFO + for normal signals too. */ + +/* When the SH Linux kernel calls a signal handler and the + SA_RESTORER flag isn't set, the return address points to a bit of + code on the stack. This function returns whether the PC appears to + be within this bit of code. + + The instruction sequence for normal signals is + mov.w 1f,r3 + trapa #16 + or r0, r0 + or r0, r0 + or r0, r0 + or r0, r0 + or r0, r0 + 1: .word __NR_sigreturn + or 0x9305 0xc310 0x200b 0x200b 0x200b 0x200b 0x200b 0x0077. + + Checking for the code sequence should be somewhat reliable, because + the effect is to call the system call sigreturn. This is unlikely + to occur anywhere other than a signal trampoline. + + It kind of sucks that we have to read memory from the process in + order to identify a signal trampoline, but there doesn't seem to be + any other way. The PC_IN_SIGTRAMP macro in tm-linux.h arranges to + only call us if no function name could be identified, which should + be the case since the code is on the stack. + + Detection of signal trampolines for handlers that set the + SA_RESTORER flag is in general not possible. Unfortunately this is + what the GNU C Library has been doing for quite some time now. + However, as of version 2.1.2, the GNU C Library uses signal + trampolines (named __restore and __restore_rt) that are identical + to the ones used by the kernel. Therefore, these trampolines are + supported too. */ + +#define MOVW(n) (0x9300|((n)-2)) /* Move mem word at PC+n to R3 */ +#define TRAP16 0xc310 /* Syscall w/no args (NR in R3) */ +#define OR_R0_R0 0x200b /* or r0,r0 (insert to avoid hardware bug) */ + +#define LINUX_SIGTRAMP_INSN0 MOVW(7) /* Move mem word at PC+7 to R3 */ +#define LINUX_SIGTRAMP_INSN1 TRAP16 /* Syscall w/no args (NR in R3) */ +#define LINUX_SIGTRAMP_INSN2 OR_R0_R0 /* or r0,r0 (insert to avoid hardware bug) */ + +static const unsigned short linux_sigtramp_code[] = +{ + LINUX_SIGTRAMP_INSN0, + LINUX_SIGTRAMP_INSN1, + LINUX_SIGTRAMP_INSN2, + LINUX_SIGTRAMP_INSN2, + LINUX_SIGTRAMP_INSN2, + LINUX_SIGTRAMP_INSN2, + LINUX_SIGTRAMP_INSN2, + __NR_sigreturn +}; + +#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code) + +/* If PC is in a sigtramp routine, return the address of the start of + the routine. Otherwise, return 0. */ + +static CORE_ADDR +sh_linux_sigtramp_start (struct frame_info *next_frame) +{ + CORE_ADDR pc = get_frame_pc (next_frame); + gdb_byte buf[LINUX_SIGTRAMP_LEN]; + + /* We only recognize a signal trampoline if PC is at the start of + one of the three instructions. We optimize for finding the PC at + the start, as will be the case when the trampoline is not the + first frame on the stack. We assume that in the case where the + PC is not at the start of the instruction sequence, there will be + a few trailing readable bytes on the stack. */ + + if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN)) + return 0; + + if (buf[0] != LINUX_SIGTRAMP_INSN0) + { + if (buf[0] != LINUX_SIGTRAMP_INSN1) + return 0; + + pc -= 2; + + if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN)) + return 0; + } + + if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0) + return 0; + + return pc; +} + +/* This function does the same for RT signals. Here the instruction + sequence is + mov.w 1f,r3 + trapa #16 + or r0, r0 + or r0, r0 + or r0, r0 + or r0, r0 + or r0, r0 + 1: .word __NR_rt_sigreturn + or 0x9305 0xc310 0x200b 0x200b 0x200b 0x200b 0x200b 0x00ad. + + The effect is to call the system call rt_sigreturn. */ + +#define LINUX_RT_SIGTRAMP_INSN0 MOVW(7) /* Move mem word at PC+7 to R3 */ +#define LINUX_RT_SIGTRAMP_INSN1 TRAP16 /* Syscall w/no args (NR in R3) */ +#define LINUX_RT_SIGTRAMP_INSN2 OR_R0_R0 /* or r0,r0 (insert to avoid hardware bug) */ + +static const unsigned short linux_rt_sigtramp_code[] = +{ + LINUX_RT_SIGTRAMP_INSN0, + LINUX_RT_SIGTRAMP_INSN1, + LINUX_RT_SIGTRAMP_INSN2, + LINUX_RT_SIGTRAMP_INSN2, + LINUX_RT_SIGTRAMP_INSN2, + LINUX_RT_SIGTRAMP_INSN2, + LINUX_RT_SIGTRAMP_INSN2, + __NR_rt_sigreturn +}; + +#define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code) + +/* If PC is in a RT sigtramp routine, return the address of the start + of the routine. Otherwise, return 0. */ + +static CORE_ADDR +sh_linux_rt_sigtramp_start (struct frame_info *next_frame) +{ + CORE_ADDR pc = get_frame_pc (next_frame); + gdb_byte buf[LINUX_RT_SIGTRAMP_LEN]; + + /* We only recognize a signal trampoline if PC is at the start of + one of the two instructions. We optimize for finding the PC at + the start, as will be the case when the trampoline is not the + first frame on the stack. We assume that in the case where the + PC is not at the start of the instruction sequence, there will be + a few trailing readable bytes on the stack. */ + + if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_RT_SIGTRAMP_LEN)) + return 0; + + if (buf[0] != LINUX_RT_SIGTRAMP_INSN0) + { + if (buf[0] != LINUX_RT_SIGTRAMP_INSN1) + return 0; + + pc -= 2; + + if (!safe_frame_unwind_memory (next_frame, pc, buf, + LINUX_RT_SIGTRAMP_LEN)) + return 0; + } + + if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0) + return 0; + + return pc; +} + +/* Return whether PC is in a GNU/Linux sigtramp routine. */ + +static int +sh_linux_sigtramp_p (struct frame_info *this_frame) +{ + CORE_ADDR pc = get_frame_pc (this_frame); + char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + + /* If we have NAME, we can optimize the search. The trampolines are + named __restore and __restore_rt. However, they aren't dynamically + exported from the shared C library, so the trampoline may appear to + be part of the preceding function. This should always be sigaction, + __sigaction, or __libc_sigaction (all aliases to the same function). */ + if (name == NULL || strstr (name, "sigaction") != NULL) + return (sh_linux_sigtramp_start (this_frame) != 0 + || sh_linux_rt_sigtramp_start (this_frame) != 0); + + return (strcmp ("__restore", name) == 0 + || strcmp ("__restore_rt", name) == 0); +} + +/* Offset to struct sigcontext in ucontext, from . */ +#define SH_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 12 + + +/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp + routine, return the address of the associated sigcontext structure. */ + +static CORE_ADDR +sh_linux_sigcontext_addr (struct frame_info *this_frame) +{ + CORE_ADDR pc; + CORE_ADDR sp; + + sp = get_frame_register_unsigned (this_frame, SP_REGNUM); + + pc = sh_linux_sigtramp_start (this_frame); + if (pc) + { + return sp; + } + + pc = sh_linux_rt_sigtramp_start (this_frame); + if (pc) + { + CORE_ADDR ucontext_addr; + + /* The sigcontext structure is part of the user context. A + pointer to the user context is passed as the third argument + to the signal handler. */ + ucontext_addr = get_frame_register_unsigned (this_frame, ARG0_REGNUM+2); + return ucontext_addr + SH_LINUX_UCONTEXT_SIGCONTEXT_OFFSET; + } + + error ("Couldn't recognize signal trampoline."); + return 0; +} + +/* Signal trampolines. */ +extern struct sh_frame_cache *sh_alloc_frame_cache (void); + +static struct sh_frame_cache * +sh_linux_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache) +{ + struct sh_frame_cache *cache; + struct gdbarch_tdep *tdep = gdbarch_tdep (get_current_arch ()); + CORE_ADDR sigcontext_addr; + + if (*this_cache) + return *this_cache; + + cache = sh_alloc_frame_cache (); + + cache->base = get_frame_register_unsigned (this_frame, SP_REGNUM); + sigcontext_addr = tdep->sigcontext_addr (this_frame); + if (tdep->sc_reg_offset) + { + int i; + + gdb_assert (tdep->sc_num_regs <= SH_NUM_REGS); + + for (i = 0; i < tdep->sc_num_regs; i++) + if (tdep->sc_reg_offset[i] != -1) + cache->saved_regs[i] = sigcontext_addr + tdep->sc_reg_offset[i]; + } + + *this_cache = cache; + return cache; +} + +static void +sh_linux_sigtramp_frame_this_id (struct frame_info *this_frame, void **this_cache, + struct frame_id *this_id) +{ + struct sh_frame_cache *cache = + sh_linux_sigtramp_frame_cache (this_frame, this_cache); + + (*this_id) = frame_id_build (cache->base + 64, cache->pc); +} + +extern struct value * sh_frame_prev_register (); +static struct value * +sh_linux_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + sh_linux_sigtramp_frame_cache (this_frame, this_cache); + + return sh_frame_prev_register (this_frame, this_cache, regnum); +} + +static int +sh_linux_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame)); + + /* We shouldn't even bother if we don't have a sigcontext_addr + handler. */ + if (tdep->sigcontext_addr == NULL) + return 0; + + if (tdep->sigtramp_p != NULL) + { + if (tdep->sigtramp_p (this_frame)) + return 1; + } + + return 0; +} + +static const struct frame_unwind sh_linux_sigtramp_frame_unwind = +{ + SIGTRAMP_FRAME, + sh_linux_sigtramp_frame_this_id, + sh_linux_sigtramp_frame_prev_register, + NULL, + sh_linux_sigtramp_frame_sniffer +}; + +/* Supply register REGNUM from the buffer specified by GREGS and LEN + in the general-purpose register set REGSET to register cache + REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ + +void +sh_supply_gregset (const struct regset *regset, struct regcache *regcache, + int regnum, const void *gregs, size_t len) +{ + const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); + const char *regs = gregs; + int i; + + gdb_assert (len == tdep->sizeof_gregset); + + for (i = 0; i < tdep->gregset_num_regs; i++) + { + if ((regnum == i || regnum == -1) + && tdep->gregset_reg_offset[i] != -1) + regcache_raw_supply (regcache, i, regs + tdep->gregset_reg_offset[i]); + } +} + +/* Collect register REGNUM from the register cache REGCACHE and store + it in the buffer specified by GREGS and LEN as described by the + general-purpose register set REGSET. If REGNUM is -1, do this for + all registers in REGSET. */ + +void +sh_collect_gregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs, size_t len) +{ + const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); + char *regs = gregs; + int i; + + gdb_assert (len == tdep->sizeof_gregset); + + for (i = 0; i < tdep->gregset_num_regs; i++) + { + if ((regnum == i || regnum == -1) + && tdep->gregset_reg_offset[i] != -1) + regcache_raw_collect (regcache, i, regs + tdep->gregset_reg_offset[i]); + } +} + +/* Supply register REGNUM from the buffer specified by FPREGS and LEN + in the floating-point register set REGSET to register cache + REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ + +static void +sh_supply_fpregset (const struct regset *regset, struct regcache *regcache, + int regnum, const void *fpregs, size_t len) +{ + const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); + const char *regs = fpregs; + int i; + + gdb_assert (len == tdep->sizeof_fpregset); + for (i = 0; i < 16; i++) + { + if (regnum == i+25 || regnum == -1) + regcache_raw_supply (regcache, i+25, regs + i*4); + } + if (regnum == FPSCR_REGNUM || regnum == -1) + regcache_raw_supply (regcache, FPSCR_REGNUM, regs + 32*4); + if (regnum == FPUL_REGNUM || regnum == -1) + regcache_raw_supply (regcache, FPUL_REGNUM, regs + 33*4); +} + +/* Collect register REGNUM from the register cache REGCACHE and store + it in the buffer specified by FPREGS and LEN as described by the + floating-point register set REGSET. If REGNUM is -1, do this for + all registers in REGSET. */ + +static void +sh_collect_fpregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *fpregs, size_t len) +{ + const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); + char *regs = fpregs; + int i; + + gdb_assert (len == tdep->sizeof_fpregset); + for (i = 0; i < 16; i++) + { + if (regnum == i+25 || regnum == -1) + regcache_raw_collect (regcache, i+25, regs + i*4); + } + if (regnum == FPSCR_REGNUM || regnum == -1) + regcache_raw_collect (regcache, FPSCR_REGNUM, regs + 32*4); + if (regnum == FPUL_REGNUM || regnum == -1) + regcache_raw_collect (regcache, FPUL_REGNUM, regs + 33*4); +} + +/* Return the appropriate register set for the core section identified + by SECT_NAME and SECT_SIZE. */ + +const struct regset * +sh_linux_regset_from_core_section (struct gdbarch *gdbarch, + const char *sect_name, size_t sect_size) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (strcmp (sect_name, ".reg") == 0 && sect_size == tdep->sizeof_gregset) + { + if (tdep->gregset == NULL) + tdep->gregset = regset_alloc (gdbarch, sh_supply_gregset, + sh_collect_gregset); + return tdep->gregset; + } + + if ((strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)) + { + if (tdep->fpregset == NULL) + tdep->fpregset = regset_alloc (gdbarch, sh_supply_fpregset, + sh_collect_fpregset); + return tdep->fpregset; + } + + return NULL; +} + +/* The register sets used in GNU/Linux ELF core-dumps are identical to + the register sets in `struct user' that are used for a.out + core-dumps. These are also used by ptrace(2). The corresponding + types are `elf_gregset_t' for the general-purpose registers (with + `elf_greg_t' the type of a single GP register) and `elf_fpregset_t' + for the floating-point registers. + + Those types used to be available under the names `gregset_t' and + `fpregset_t' too, and GDB used those names in the past. But those + names are now used for the register sets used in the `mcontext_t' + type, which have a different size and layout. */ + +/* Mapping between the general-purpose registers in `struct user' + format and GDB's register cache layout. */ + +/* From . */ +static int sh_linux_gregset_reg_offset[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, + + REG_PC*4, REG_PR*4, REG_GBR*4, -1, + REG_MACH*4, REG_MACL*4, REG_SR*4, +}; + +/* Mapping between the general-purpose registers in `struct + sigcontext' format and GDB's register cache layout. */ + +/* From . */ +static int sh_linux_sc_reg_offset[] = +{ + 4, 8, 12, 16, 20, 24, 28, 32, + 36, 40, 44, 48, 52, 56, 60, 64, + 68, 72, 80, -1, + 84, 88, 76 +}; + static void sh_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + bfd abfd; + + tdep->gregset_reg_offset = sh_linux_gregset_reg_offset; + tdep->gregset_num_regs = ARRAY_SIZE (sh_linux_gregset_reg_offset); + tdep->sizeof_gregset = 23 * 4; + + tdep->jb_pc_offset = 32; /* From . */ + + tdep->sigtramp_p = sh_linux_sigtramp_p; + tdep->sigcontext_addr = sh_linux_sigcontext_addr; + tdep->sc_reg_offset = sh_linux_sc_reg_offset; + tdep->sc_num_regs = ARRAY_SIZE (sh_linux_sc_reg_offset); + + frame_unwind_append_unwinder(gdbarch, &sh_linux_sigtramp_frame_unwind); + + /* If we have a register mapping, enable the generic core file + support, unless it has already been enabled. */ + if (tdep->gregset_reg_offset + && !gdbarch_regset_from_core_section_p (gdbarch)) + set_gdbarch_regset_from_core_section (gdbarch, + sh_linux_regset_from_core_section); + linux_init_abi (info, gdbarch); /* GNU/Linux uses SVR4-style shared libraries. */ diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c index 2c2b26847d..14f5281ed4 100644 --- a/gdb/sh-tdep.c +++ b/gdb/sh-tdep.c @@ -21,6 +21,9 @@ sac@cygnus.com. */ #include "defs.h" +#include "arch-utils.h" +#include "command.h" +#include "dummy-frame.h" #include "frame.h" #include "frame-base.h" #include "frame-unwind.h" @@ -35,6 +38,7 @@ #include "arch-utils.h" #include "floatformat.h" #include "regcache.h" +#include "regset.h" #include "doublest.h" #include "osabi.h" #include "reggroups.h" @@ -68,23 +72,6 @@ static const char *const sh_cc_enum[] = { static const char *sh_active_calling_convention = sh_cc_gcc; -#define SH_NUM_REGS 67 - -struct sh_frame_cache -{ - /* Base address. */ - CORE_ADDR base; - LONGEST sp_offset; - CORE_ADDR pc; - - /* Flag showing that a frame has been created in the prologue code. */ - int uses_fp; - - /* Saved registers. */ - CORE_ADDR saved_regs[SH_NUM_REGS]; - CORE_ADDR saved_sp; -}; - static int sh_is_renesas_calling_convention (struct type *func_type) { @@ -1052,7 +1039,7 @@ sh_treat_as_flt_p (struct type *type) return 0; /* Otherwise if the type of that member is float, the whole type is treated as float. */ - if (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT) + if (TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, 0))) == TYPE_CODE_FLT) return 1; /* Otherwise it's not treated as float. */ return 0; @@ -1102,7 +1089,7 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch, in four registers available. Loop thru args from first to last. */ for (argnum = 0; argnum < nargs; argnum++) { - type = value_type (args[argnum]); + type = check_typedef (value_type (args[argnum])); len = TYPE_LENGTH (type); val = sh_justify_value_in_reg (gdbarch, args[argnum], len); @@ -1828,7 +1815,7 @@ sh_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, reg->how = DWARF2_FRAME_REG_UNDEFINED; } -static struct sh_frame_cache * +struct sh_frame_cache * sh_alloc_frame_cache (void) { struct sh_frame_cache *cache; @@ -1855,7 +1842,7 @@ sh_alloc_frame_cache (void) return cache; } -static struct sh_frame_cache * +struct sh_frame_cache * sh_frame_cache (struct frame_info *this_frame, void **this_cache) { struct gdbarch *gdbarch = get_frame_arch (this_frame); @@ -1922,9 +1909,9 @@ sh_frame_cache (struct frame_info *this_frame, void **this_cache) return cache; } -static struct value * -sh_frame_prev_register (struct frame_info *this_frame, - void **this_cache, int regnum) +struct value * +sh_frame_prev_register (struct frame_info *this_frame, void **this_cache, + int regnum) { struct gdbarch *gdbarch = get_frame_arch (this_frame); struct sh_frame_cache *cache = sh_frame_cache (this_frame, this_cache); @@ -1938,7 +1925,7 @@ sh_frame_prev_register (struct frame_info *this_frame, the current frame. Frob regnum so that we pull the value from the correct place. */ if (regnum == gdbarch_pc_regnum (gdbarch)) - regnum = PR_REGNUM; + regnum = PR_REGNUM; /* XXX: really? */ if (regnum < SH_NUM_REGS && cache->saved_regs[regnum] != -1) return frame_unwind_got_memory (this_frame, regnum, @@ -2247,8 +2234,8 @@ sh_return_in_first_hidden_param_p (struct gdbarch *gdbarch, static struct gdbarch * sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { - struct gdbarch *gdbarch; struct gdbarch_tdep *tdep; + struct gdbarch *gdbarch; /* SH5 is handled entirely in sh64-tdep.c. */ if (info.bfd_arch_info->mach == bfd_mach_sh5) @@ -2264,6 +2251,18 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep = XCNEW (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); + /* General-purpose registers. */ + tdep->gregset = NULL; + tdep->gregset_reg_offset = NULL; + tdep->gregset_num_regs = 23; + tdep->sizeof_gregset = 0; + + /* Floating-point registers. */ + tdep->fpregset = NULL; + tdep->sizeof_fpregset = 34*4; + + tdep->jb_pc_offset = -1; + set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT); set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT); set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT); @@ -2418,10 +2417,11 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) break; } + dwarf2_append_unwinders (gdbarch); + /* Hook in ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); - dwarf2_append_unwinders (gdbarch); frame_unwind_append_unwinder (gdbarch, &sh_stub_unwind); frame_unwind_append_unwinder (gdbarch, &sh_frame_unwind); diff --git a/gdb/sh-tdep.h b/gdb/sh-tdep.h index d15ef050e0..c4642cefa4 100644 --- a/gdb/sh-tdep.h +++ b/gdb/sh-tdep.h @@ -21,6 +21,12 @@ /* Contributed by Steve Chamberlain sac@cygnus.com. */ +struct frame_info; +struct gdbarch; +struct reggroup; +struct regset; +struct regcache; + /* Registers for all SH variants. Used also by sh3-rom.c. */ enum { @@ -29,6 +35,7 @@ enum ARG0_REGNUM = 4, ARGLAST_REGNUM = 7, FP_REGNUM = 14, + SP_REGNUM = 15, PC_REGNUM = 16, PR_REGNUM = 17, GBR_REGNUM = 18, @@ -81,6 +88,24 @@ enum FV0_REGNUM = 76, FV_LAST_REGNUM = 79 }; +#define SH_NUM_REGS 67 + +struct sh_frame_cache +{ + /* Base address. */ + CORE_ADDR base; + LONGEST sp_offset; + CORE_ADDR pc; + + /* Flag showing that a frame has been created in the prologue code. */ + int uses_fp; + + /* Saved registers. */ + CORE_ADDR saved_regs[SH_NUM_REGS]; + CORE_ADDR saved_sp; +}; + +extern struct sh_frame_cache *sh_frame_cache (struct frame_info *next_frame, void **this_cache); /* This structure describes a register in a core-file. */ struct sh_corefile_regmap @@ -89,8 +114,32 @@ struct sh_corefile_regmap unsigned int offset; }; +/* sh architecture specific information. */ struct gdbarch_tdep { + /* General-purpose registers. */ + struct regset *gregset; + int *gregset_reg_offset; + int gregset_num_regs; + size_t sizeof_gregset; + + /* Floating-point registers. */ + struct regset *fpregset; + size_t sizeof_fpregset; + + /* Offset of saved PC in jmp_buf. */ + int jb_pc_offset; + + /* Detect sigtramp. */ + int (*sigtramp_p) (struct frame_info *); + + /* Get address of sigcontext for sigtramp. */ + CORE_ADDR (*sigcontext_addr) (struct frame_info *); + + /* Offset of registers in `struct sigcontext'. */ + int *sc_reg_offset; + int sc_num_regs; + /* Non-NULL when debugging from a core file. Provides the offset where each general-purpose register is stored inside the associated core file section. */ diff --git a/gdb/testsuite/gdb.asm/asm-source.exp b/gdb/testsuite/gdb.asm/asm-source.exp index e07e5543f2..f5e60e1002 100644 --- a/gdb/testsuite/gdb.asm/asm-source.exp +++ b/gdb/testsuite/gdb.asm/asm-source.exp @@ -116,6 +116,11 @@ switch -glob -- [istarget] { append link-flags " -m elf32ppc" } } + "sh*-linux*" { + set asm-arch sh-linux + set asm-flags "-I${srcdir}/${subdir} -I${objdir}/${subdir}" + set debug-flags "-gdwarf-2" + } "sh*-*-*" { set asm-arch sh set debug-flags "-gdwarf-2" diff --git a/gdb/testsuite/gdb.asm/sh.inc b/gdb/testsuite/gdb.asm/sh.inc index a4a5fc545e..89efed7795 100644 --- a/gdb/testsuite/gdb.asm/sh.inc +++ b/gdb/testsuite/gdb.asm/sh.inc @@ -40,9 +40,8 @@ mov.l .Lconst\@,r1 bra .Lafterconst\@ nop - nop -.Lconst\@: .align 2 +.Lconst\@: .long \subr .align 1 .Lafterconst\@: diff --git a/gdb/testsuite/gdb.base/annota1.c b/gdb/testsuite/gdb.base/annota1.c index 424e1b8327..0de2e7b633 100644 --- a/gdb/testsuite/gdb.base/annota1.c +++ b/gdb/testsuite/gdb.base/annota1.c @@ -1,6 +1,9 @@ #include #include +#ifdef __sh__ +#define signal(a,b) /* Signals not supported on this target - make them go away */ +#endif void handle_USR1 (int sig) diff --git a/gdb/testsuite/gdb.base/annota3.c b/gdb/testsuite/gdb.base/annota3.c index 424e1b8327..952aaf218a 100644 --- a/gdb/testsuite/gdb.base/annota3.c +++ b/gdb/testsuite/gdb.base/annota3.c @@ -1,6 +1,10 @@ #include #include +#ifdef __sh__ +#define signal(a,b) /* Signals not supported on this target - make them go away */ +#endif + void handle_USR1 (int sig) diff --git a/gdb/testsuite/gdb.base/sigall.c b/gdb/testsuite/gdb.base/sigall.c index 81f3b08d6b..1574b2d6cb 100644 --- a/gdb/testsuite/gdb.base/sigall.c +++ b/gdb/testsuite/gdb.base/sigall.c @@ -1,6 +1,9 @@ #include #include +#ifdef __sh__ +#define signal(a,b) /* Signals not supported on this target - make them go away */ +#endif /* Signal handlers, we set breakpoints in them to make sure that the signals really get delivered. */ diff --git a/gdb/testsuite/gdb.base/signals.c b/gdb/testsuite/gdb.base/signals.c index 756606880f..1205a9bc9c 100644 --- a/gdb/testsuite/gdb.base/signals.c +++ b/gdb/testsuite/gdb.base/signals.c @@ -3,6 +3,10 @@ #include #include +#ifdef __sh__ +#define signal(a,b) /* Signals not supported on this target - make them go away */ +#define alarm(a) /* Ditto for alarm() */ +#endif static int count = 0; -- 2.13.1