[PATCH] Renesas SH (sh4) native support

Yao Qi yao@codesourcery.com
Sun Nov 20 07:10:00 GMT 2011


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 <http://www.gnu.org/licenses/>.  */
>  
>  #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 <sys/ptrace.h>
> +#include <sys/types.h>
> +#include <sys/param.h>
> +#include <sys/user.h>
> +#include <sys/syscall.h>
> +
> +#include <asm/ptrace.h>
> +
> +#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 <asm/ucontext.h>.  */
> +#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 <sys/reg.h>.  */
> +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 <asm/sigcontext.h>.  */
> +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 <bits/setjmp.h>.  */
> +
> +  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 (齐尧)



More information about the Gdb-patches mailing list