From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22447 invoked by alias); 20 Nov 2011 07:10:13 -0000 Received: (qmail 22428 invoked by uid 22791); 20 Nov 2011 07:10:08 -0000 X-SWARE-Spam-Status: No, hits=-1.1 required=5.0 tests=AWL,BAYES_00,SARE_BAYES_6x6,SARE_BAYES_7x6,TW_EG,TW_GJ X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 20 Nov 2011 07:09:51 +0000 Received: from nat-jpt.mentorg.com ([192.94.33.2] helo=PR1-MAIL.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1RS1XB-0002M4-Qw from Yao_Qi@mentor.com ; Sat, 19 Nov 2011 23:09:50 -0800 Received: from [127.0.0.1] ([172.16.63.104]) by PR1-MAIL.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.1830); Sun, 20 Nov 2011 16:09:46 +0900 Message-ID: <4EC8A7AA.2020101@codesourcery.com> Date: Sun, 20 Nov 2011 07:10:00 -0000 From: Yao Qi User-Agent: Mozilla/5.0 (X11; Linux i686; rv:7.0.1) Gecko/20110930 Thunderbird/7.0.1 MIME-Version: 1.0 To: Hector Oron CC: gdb-patches@sourceware.org, Nobuhiro Iwamatsu , yoshii.takashi@renesas.com Subject: Re: [PATCH] Renesas SH (sh4) native support References: <20111117232006.GA22252@enorme.TCLDOMAIN.OFFICE> In-Reply-To: <20111117232006.GA22252@enorme.TCLDOMAIN.OFFICE> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-11/txt/msg00533.txt.bz2 On 11/18/2011 07:20 AM, Hector Oron wrote: > You may also have to provide an entry in gdb/NEWS to mention this change. > --- gdb-7.4.orig/gdb/sh-linux-tdep.c > +++ gdb-7.4/gdb/sh-linux-tdep.c > @@ -19,11 +19,34 @@ > 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 > +#include > +#include > +#include > +#include > + > +#include > + > +#include "regset.h" > #include "glibc-tdep.h" > #include "sh-tdep.h" > #include "linux-tdep.h" > @@ -71,9 +94,505 @@ static const struct sh_corefile_regmap f > {-1 /* Terminator. */, 0} > }; > > +/* 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; > + } braces are not needed here. We can, 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); ^^ Need extra spaces around "+". > + 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 ()); We should call get_frame_arch (this_frame) to get gdbarch instead of 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); This statement above can be moved into "if block" below. > + 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); I am not familiar with SH, but "64" is magic number to me. We may either add a comment here or replace this magic number with a macro. > +} > + > +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) Wrong indentation. > +{ > + 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) Wrong indentation, and other places below. > +{ > + 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 Can it be "static"? > +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) We may need extra parentheses so that the indentation shows the nesting, like this, 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); Spaces are need around "+" and "*", and below > + } > + 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[] = static const int h_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[] = static const. > +{ > + 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); Why do we need checking !gdbarch_regset_from_core_section_p (gdbarch) ? > + > linux_init_abi (info, gdbarch); > > /* GNU/Linux uses SVR4-style shared libraries. */ > --- gdb-7.4.orig/gdb/sh-tdep.h > +++ gdb-7.4/gdb/sh-tdep.h > @@ -22,6 +22,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 > { > @@ -30,6 +36,7 @@ enum > ARG0_REGNUM = 4, > ARGLAST_REGNUM = 7, > FP_REGNUM = 14, > + SP_REGNUM = 15, > PC_REGNUM = 16, > PR_REGNUM = 17, > GBR_REGNUM = 18, > @@ -83,8 +90,26 @@ enum > 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 gdbarch_init_ftype sh64_gdbarch_init; > extern void sh64_show_regs (struct frame_info *); > +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 > @@ -93,8 +118,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; First of all, I don't find this field is used in your patch. I guess it is going to be used in get_longjmp_target gdbarch method. Secondly, `jp_pc_offset' is only set to 32 in this patch, so it looks like a constant to me. If the "pc offset in jump buffer" is an invariant, we can use a const directly. > + > + /* 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. */ > --- gdb-7.4.orig/gdb/sh-tdep.c > +++ gdb-7.4/gdb/sh-tdep.c > @@ -2611,7 +2598,7 @@ sh_frame_prev_register (struct frame_inf > 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? */ Why leave that comment here? > > if (regnum < SH_NUM_REGS && cache->saved_regs[regnum] != -1) > return frame_unwind_got_memory (this_frame, regnum, > @@ -2855,8 +2842,8 @@ sh_regset_from_core_section (struct gdba > static struct gdbarch * > sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) > { > - struct gdbarch *gdbarch; > struct gdbarch_tdep *tdep; > + struct gdbarch *gdbarch; > Unnecessary change. > sh_show_regs = sh_generic_show_regs; > switch (info.bfd_arch_info->mach) > @@ -2919,6 +2906,18 @@ sh_gdbarch_init (struct gdbarch_info inf > tdep = XZALLOC (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); > @@ -3064,10 +3063,11 @@ sh_gdbarch_init (struct gdbarch_info inf > break; > } > > + dwarf2_append_unwinders (gdbarch); > + > /* Hook in ABI-specific overrides, if they have been registered. */ > gdbarch_init_osabi (info, gdbarch); > > - dwarf2_append_unwinders (gdbarch); Unnecessary changes. > frame_unwind_append_unwinder (gdbarch, &sh_frame_unwind); > > return gdbarch; > --- /dev/null > +++ gdb-7.4/gdb/config/sh/nm-linux.h > @@ -0,0 +1,54 @@ > +/* Native-dependent definitions for SuperH running Linux, for GDB. > + Copyright 2004 Free Software Foundation, Inc. ^^^^^^ It should be 2011. > + > + 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 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. */ > + > +#ifndef NM_LINUX_H > +#define NM_LINUX_H > + > +/* Get generic Linux native definitions. */ > +#include "config/nm-linux.h" > +/* Support for the user area. */ > + > +/* Return the size of the user struct. */ > +extern int kernel_u_size (void); > +#define KERNEL_U_SIZE kernel_u_size() > + > +/* This is the amount to substract from u.u_ar0 to get the offset in > + the core file of the register values. */ > +#define KERNEL_U_ADDR 0 > + > +#define U_REGS_OFFSET 0 > + > +extern CORE_ADDR register_u_addr (CORE_ADDR blockend, int regnum); > +#define REGISTER_U_ADDR(addr, blockend, regnum) \ > + (addr) = register_u_addr (blockend, regnum) > + > +/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'. */ > +#define FETCH_INFERIOR_REGISTERS > + > +/* Nevertheless, define CANNOT_{FETCH,STORE}_REGISTER, because we > + might fall back on the code `infptrace.c' (well a copy of that code > + in `sh-linux-nat.c' for now) and we can access only the > + general-purpose registers in that way. */ > +extern int cannot_fetch_register (int regno); > +extern int cannot_store_register (int regno); > +#define CANNOT_FETCH_REGISTER(regno) cannot_fetch_register (regno) > +#define CANNOT_STORE_REGISTER(regno) cannot_store_register (regno) > + > +#endif /* NM_LINUX_H */ -- Yao (齐尧)