This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 1/5] Code for nds32 target


On 07/08/2013 05:27 PM, Wei-cheng Wang wrote:

Here is the 2nd half.

+/* Implement the gdbarch_register_reggroup_p method.  */
+
+static int
+nds32_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+			   struct reggroup *group)
+{
+  int i;
+  struct reggroup *groups[] =
+  {
+      nds32_cr_reggroup, nds32_ir_reggroup, nds32_mr_reggroup,
+      nds32_dr_reggroup, nds32_pfr_reggroup, nds32_dmar_reggroup,
+      nds32_racr_reggroup, nds32_idr_reggroup
+  };
+  static const char *prefix[] =
+  {
+      "cr", "ir", "mr", "dr", "pfr", "dmar", "racr", "idr"
+  };
+
+  gdb_assert (sizeof (groups) == sizeof (prefix));

gdb_assert (ARRAY_SIZE (groups) == ARRAY_SIZE (prefix)); ?

+
+  /* GPRs. */
+  if (group == general_reggroup)
+    return regnum <= NDS32_PC_REGNUM;
+
+  /* System Registers are grouped by prefix.  */
+  else if (group == system_reggroup)
+    return (regnum > NDS32_PC_REGNUM)
+	   && TYPE_CODE (register_type (gdbarch, regnum)) != TYPE_CODE_FLT;
+
+  for (i = 0; i < ARRAY_SIZE (groups); i++)
+    {
+      if (group == groups[i])
+	{
+	  const char *regname = tdesc_register_name (gdbarch, regnum);
+
+	  if (!regname)
+	    return 0;
+	  return strstr (regname, prefix[i]) == regname;
+	}
+    }
+
+  return default_register_reggroup_p (gdbarch, regnum, group);
+}
+
+/* This function is called when
+   1. Target-description is used, and the register is pseudo.
+   2. Target-description is NOT used,
+       i. and the target is simulator.
+      ii. or the target is legacy target.  */
+
+/* Implement the tdesc_pseudo_register_name method.  */
+
+static const char *
+nds32_register_name (struct gdbarch *gdbarch, int regnum)
+{
+  static char *fpu_pseudo_names[] =
+  {
+    "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
+    "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
+    "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23",
+    "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31"
+  };
+  static char *sim_names[] =
+  {
+    "fd0", "fd1", "fd2", "fd3", "fd4", "fd5", "fd6", "fd7",
+    "fd8", "fd9", "fd10", "fd11", "fd12", "fd13", "fd14", "fd15",
+    "fd16", "fd17", "fd18", "fd19", "fd20", "fd21", "fd22", "fd23",
+    "fd24", "fd25", "fd26", "fd27", "fd28", "fd29", "fd30", "fd31",
+    "ifclp", "itb", "ir0"
+  };
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int num_regs = gdbarch_num_regs (gdbarch);
+
+  /* Currently, only pseudo FSR are supported.  */
+  if (regnum >= num_regs && regnum < num_regs + 32)
+    return fpu_pseudo_names[regnum - num_regs];
+
+  /* GPRs.  */
+  if (regnum < ARRAY_SIZE (nds32_regnames))
+    return nds32_regnames[regnum];
+
+  /* Registers beteen NUM_REGS and SMI_NUM_REGS are
+     simulator registers.  */
+  if (regnum >= NDS32_NUM_REGS && regnum < NDS32_SIM_NUM_REGS)
+    return sim_names[regnum - NDS32_NUM_REGS];
+
+  warning (_("Unknown nds32 pseudo register %d."), regnum);
+  return NULL;
+}
+
+/* Implement the gdbarch_pseudo_register_read method.
+
+   For legacy target, target-description and FPRs are not support.
+   Use Rcmd to access FPU registers.  */
+
+static enum register_status
+nds32_pseudo_register_read (struct gdbarch *gdbarch,
+			    struct regcache *regcache, int regnum,
+			    gdb_byte *buf)
+{
+  char name_buf[8];
+  gdb_byte reg_buf[8];
+  int offset;
+  enum register_status status = REG_UNKNOWN;
+
+  /* Sanity check.  */
+  regnum -= gdbarch_num_regs (gdbarch);
+  if (regnum > gdbarch_num_pseudo_regs (gdbarch))
+    return status;
+
+  /* Currently, only FSR are supported.  */
+  if (regnum < 32)
+    {
+      int fd_regnum;
+
+      /* fs0 is always the high-part of fd0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = (regnum & 1) ? 4 : 0;
+      else
+	offset = (regnum & 1) ? 0 : 4;
+
+      sprintf (name_buf, "fd%d", regnum >> 1);

xsnprintf

+      fd_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+					       strlen (name_buf));
+      status = regcache_raw_read (regcache, fd_regnum, reg_buf);
+      if (status == REG_VALID)
+	memcpy (buf, reg_buf + offset, 4);
+    }
+
+  return status;
+}
+
+/* Implement the gdbarch_pseudo_register_write method.  */
+
+static void
+nds32_pseudo_register_write (struct gdbarch *gdbarch,
+			     struct regcache *regcache, int regnum,
+			     const gdb_byte *buf)
+{
+  char name_buf[8];
+  gdb_byte reg_buf[8];
+  int offset;
+
+  /* Sanity check.  */
+  regnum -= gdbarch_num_regs (gdbarch);
+  if (regnum > gdbarch_num_pseudo_regs (gdbarch))
+    return;
+
+  /* Currently, only FSR are supported.  */
+  if (regnum < 32)
+    {
+      int fd_regnum;
+
+      /* fs0 is always the high-part of fd0.  */
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = (regnum & 1) ? 4 : 0;
+      else
+	offset = (regnum & 1) ? 0 : 4;
+
+      sprintf (name_buf, "fd%d", regnum >> 1);
+      fd_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+					       strlen (name_buf));
+      regcache_raw_read (regcache, fd_regnum, reg_buf);
+      memcpy (reg_buf + offset, buf, 4);
+      regcache_raw_write (regcache, fd_regnum, reg_buf);
+    }
+
+  return;
+}
+
+/* Skip prologue should be conservative, and frame-unwind should be
+   relative-aggressive.*/
+
+static int
+nds32_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
+			CORE_ADDR scan_limit, CORE_ADDR *pl_endptr)
+{
+  uint32_t insn;
+  CORE_ADDR cpc = -1;		/* Candidate PC if no suitable PC is found.  */
+  LONGEST return_value;
+
+  /* If there is no buffer to store result, ignore this prologue decoding.  */
+  if (pl_endptr == NULL)
+    {
+      return 0;
+    }
+
+  /* Look up end of prologue */
+  for (; pc < scan_limit; )
+    {
+      insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
+
+      if ((insn & 0x80000000) == 0)
+	{
+	  /* 32-bit instruction */
+
+	  pc += 4;
+	  if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP))
+	    {
+	      /* add $gp, $ta, $gp */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_SP, REG_SP, 0))
+	    {
+	      /* addi $sp, $sp, imm15 */
+	      cpc = pc;
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_FP, REG_FP, 0))
+	    {
+	      /* addi $fp, $sp, imm15 */
+	      cpc = pc;
+	      continue;
+	    }
+	  else if (insn == N32_ALU2 (MFUSR, REG_TA, 31, 0))
+	    {
+	      /* mfusr $ta, PC  ; group=0, sub=0x20=mfusr */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
+	    {
+	      /* movi $ta, imm20s */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
+	    {
+	      /* sethi $gp, imm20 */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
+	    {
+	      /* ori $gp, $gp, imm15 */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI, REG_LP, REG_FP, 0))
+	    {
+	      /* Unlike swi, we should stop when lwi.  */
+	      /* swi $lp, [$sp + (imm15s<<2)] */
+	      continue;
+	    }
+	  else if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0))
+	    {
+	      /* swi.bi $rt, [$sp], (imm15s<<2) */
+	      continue;
+	    }
+	  else if (N32_OP6 (insn) == N32_OP6_LSMW && (insn & __BIT (5)))
+	    {
+	      /* bit-5 for SMW */
+
+	      /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */
+
+	      int rb, re, ra, enable4, i;
+	      int aligned;
+	      int m = 0;
+	      int di;		/* dec=-1 or inc=1 */
+	      char enb4map[2][4] = {
+		  {0, 1, 2, 3} /* smw */,
+		  {3, 1, 2, 0} /* smwa */};
+	      LONGEST base = ~1 + 1;
+
+	      rb = N32_RT5 (insn);
+	      ra = N32_RA5 (insn);
+	      re = N32_RB5 (insn);
+	      enable4 = (insn >> 6) & 0x0F;
+	      aligned = (insn & 3) ? 1 : 0;
+	      di = (insn & (1 << 3)) ? -1 : 1;
+
+	      switch (ra)
+		{
+		case NDS32_FP_REGNUM:
+		case NDS32_SP_REGNUM:
+		  cpc = pc;
+		  continue; /* found and continue */
+		default:
+		  break;
+		}
+	    }
+
+	  if (N32_OP6 (insn) == N32_OP6_COP && N32_COP_CP (insn) == 0
+	      && (N32_COP_SUB (insn) == N32_FPU_FSS
+		  || N32_COP_SUB (insn) == N32_FPU_FSD)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* CP shoud be CP0 */
+	      /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */
+	      continue;
+	    }
+
+	  /* fssi    $fst, [$ra + (imm12s << 2)]
+	     fssi.bi $fst, [$ra], (imm12s << 2)
+	     fsdi    $fdt, [$ra + (imm12s << 2)]
+	     fsdi.bi $fdt, [$ra], (imm12s << 2) */
+	  if ((N32_OP6 (insn) == N32_OP6_SWC || N32_OP6 (insn) == N32_OP6_SDC)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* BI bit is dont-care.  */
+	      continue;
+	    }
+
+	  pc -= 4;
+	  break;
+	}
+      else
+	{
+	  /* 16-bit instruction */
+	  pc += 2;
+	  insn >>= 16;
+
+	  /* 1. If the instruction is j/b, then we stop
+		i.e., OP starts with 10, and beqzs8, bnezs8.
+	     2. If the operations will change sp/fp or based on sp/fp,
+		then we are in the prologue.
+	     3. If we don't know what's it, then stop.  */
+
+	  if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
+	    {
+	      /* addi10s */
+	      continue;
+	    }
+	  else if (__GF (insn, 7, 8) == N16_T25_PUSH25)
+	    {
+	      /* push25 */
+	      continue;
+	    }
+	  else if (insn == N16_TYPE55 (MOV55, REG_FP, REG_SP))
+	    {
+	      /* mov55 fp, sp */
+	      continue;
+	    }
+
+	  /* swi450 */
+	  switch (insn & ~__MF (-1, 5, 4))
+	    {
+	      case N16_TYPE45 (SWI450, 0, REG_SP):
+	      case N16_TYPE45 (SWI450, 0, REG_FP):
+		break;
+	    }
+	  /* swi37 - implied fp */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* swi37sp - implied */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37SP
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* If the a instruction is not accepted,
+	     don't go futher.  */
+	  pc -= 2;
+	  break;
+	}
+    }
+
+  if (pc >= scan_limit)
+    {
+      /* If we can not find end of prologue before scan_limit,
+	 we assume that end of prologue is on pc_after_stack_adject. */
+      if (cpc != -1)
+	pc = cpc;
+    }
+
+  *pl_endptr = pc;
+
+  return 0;
+}
+
+/* Implement the gdbarch_skip_prologue method.
+
+   Find the end of function prologue.  */
+
+static CORE_ADDR
+nds32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal = { 0 };
+  LONGEST return_value;
+  const char *func_name;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  const int search_limit = 128;
+
+  /* See what the symbol table says */
+  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
+    {
+      sal = find_pc_line (func_addr, 0);
+
+      if (sal.line != 0 && sal.end <= func_end)
+	{
+	  func_end = sal.end;
+	}

Unnecessary brackets.

+      else
+	{
+	  /* Either there's no line info, or the line after the prologue
+	     is after the end of the function.  In this case, there probably
+	     isn't a prologue.  */
+	  func_end = min (func_end, func_addr + search_limit);
+	}
+    }
+  else
+    func_end = pc + search_limit;
+
+  /* If current instruction is not readable, just quit.  */
+  if (!safe_read_memory_integer (pc, 4, byte_order, &return_value))
+    return pc;
+
+  /* Find the end of prologue.  */
+  if (nds32_analyze_prologue (gdbarch, pc, func_end, &sal.end) < 0)
+    return pc;
+
+  return sal.end;
+}
+
+struct nds32_unwind_cache
+{
+  /* The previous frame's inner most stack address.
+     Used as this frame ID's stack_addr.  */
+  CORE_ADDR prev_sp;
+
+  /* The frame's base, optionally used by the high-level debug info.  */
+  CORE_ADDR base;
+  int size;
+
+  /* How far the SP and FP have been offset from the start of
+     the stack frame (as defined by the previous frame's stack
+     pointer).  */
+  LONGEST sp_offset;
+  LONGEST fp_offset;
+  int use_frame;
+
+  /* Table indicating the location of each and every register.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static struct nds32_unwind_cache *
+nds32_alloc_frame_cache (struct frame_info *this_frame)
+{
+  struct nds32_unwind_cache *cache;

Blank line is needed here.

+  cache = FRAME_OBSTACK_ZALLOC (struct nds32_unwind_cache);
+
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+  cache->size = 0;
+  cache->sp_offset = 0;
+  cache->fp_offset = 0;
+  cache->use_frame = 0;
+  cache->base = 0;
+
+  return cache;
+}
+
+/* Implement the gdbarch_in_function_epilogue_p method.  */
+
+static int
+nds32_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  uint32_t insn;
+  int r = 0;
+
+  insn = read_memory_unsigned_integer (addr, 4, BFD_ENDIAN_BIG);
+  if ((insn & 0x80000000) == 0)
+    {
+      /* 32-bit instruction */
+
+      /* ret */
+      if (insn == N32_JREG (JR, 0, REG_LP, 0, 1))
+	r = 1;
+      /* iret */
+      else if (insn == N32_TYPE0 (MISC, N32_MISC_IRET))
+	r = 2;
+    }
+  else
+    {
+      if (insn == N16_TYPE5 (RET5, REG_LP))
+	r = 3;
+    }
+  return r > 0;
+}
+
+/* Put here the code to store, into fi->saved_regs, the addresses of
+   the saved registers of frame described by FRAME_INFO.  This
+   includes special registers such as pc and fp saved in special ways
+   in the stack frame.  sp is even more special: the address we return
+   for it IS the sp for the next frame.  */
+
+static struct nds32_unwind_cache *
+nds32_frame_unwind_cache (struct frame_info *this_frame,
+			  void **this_prologue_cache)
+{
+  CORE_ADDR pc, scan_limit;
+  ULONGEST prev_sp;
+  ULONGEST next_base;
+  ULONGEST fp_base;
+  int i;
+  int insn;
+  struct nds32_unwind_cache *info;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  if ((*this_prologue_cache))
+    return (*this_prologue_cache);
+
+  info = nds32_alloc_frame_cache (this_frame);
+
+  info->base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
+  (*this_prologue_cache) = info;
+
+  if (info->base == 0)
+    return info;
+
+  pc = get_frame_func (this_frame);
+  scan_limit = get_frame_pc (this_frame);
+
+  for (; pc > 0 && pc < scan_limit; )
+    {
+      insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
+
+      if ((insn & 0x80000000) == 0)
+	{
+	  /* 32-bit instruction */
+
+	  pc += 4;
+	  if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP))
+	    {
+	      /* add $gp, $ta, $gp */
+	      continue;
+	    }
+	  if (N32_OP6 (insn) == N32_OP6_ADDI)
+	    {
+	      int rt = N32_RT5 (insn);
+	      int ra = N32_RA5 (insn);
+	      int imm15s = N32_IMM15S (insn);
+
+	      if (rt == ra && rt == NDS32_SP_REGNUM)
+		{
+		  info->sp_offset += imm15s;
+		  continue;
+		}
+	      else if (rt == NDS32_FP_REGNUM && ra == NDS32_SP_REGNUM)
+		{
+		  info->fp_offset = info->sp_offset + imm15s;
+		  info->use_frame = 1;
+		  continue;
+		}
+	      else if (rt == ra)
+		/* Prevent stop analyzing form iframe.  */
+		continue;
+	    }
+
+	  if (insn == N32_ALU2 (MFUSR, REG_TA, 31, 0))
+	    {
+	      /* mfusr $ta, PC  ; group=0, sub=0x20=mfusr */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
+	    {
+	      /* movi $ta, imm20s */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
+	    {
+	      /* sethi $gp, imm20 */
+	      continue;
+	    }
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
+	    {
+	      /* ori $gp, $gp, imm15 */
+	      continue;
+	    }
+	  if (N32_OP6 (insn) == N32_OP6_LSMW && (insn & __BIT (5)))
+	    {
+	      /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */
+
+	      int rb, re, ra, enable4, i;
+	      int aligned;
+	      int m = 0;
+	      int di;	   /* dec=-1 or inc=1 */
+	      int rn;	   /* number of registers.  */
+	      char enb4map[2][4] = {
+		  {0, 1, 2, 3} /* smw */,
+		  {3, 1, 2, 0} /* smwa */ };
+	      /* `base' is the highest/last address for access memory.
+		 e.g., [ lp ] ___ base shoule be here.
+		       [ fp ]
+		       [ r6 ] */
+	      LONGEST base = ~1 + 1;
+
+	      rb = N32_RT5 (insn);
+	      ra = N32_RA5 (insn);
+	      re = N32_RB5 (insn);
+	      enable4 = (insn >> 6) & 0x0F;
+	      aligned = (insn & 3) ? 1 : 0;
+	      di = (insn & (1 << 3)) ? -1 : 1;
+
+	      rn = 0;
+	      rn += (enable4 & 0x1) ? 1 : 0;
+	      rn += (enable4 & 0x2) ? 1 : 0;
+	      rn += (enable4 & 0x4) ? 1 : 0;
+	      rn += (enable4 & 0x8) ? 1 : 0;
+	      if (rb < NDS32_FP_REGNUM && re < NDS32_FP_REGNUM)
+		{
+		  /* reg-list should not include fp,gp,lp,sp
+		     ie, the rb==re==sp case, anyway... */
+		  rn += (re - rb) + 1;
+		}
+
+	      /* Let's consider how Ra should update.  */
+	      if (insn & (1 << 0x2))    /* m-bit is set */
+		{
+		  m = rn * 4;			/* 4*TNReg */
+		}
+	      else
+		m = 0;	  /* don't update Ra */
+
+	      switch (ra)
+		{
+		case NDS32_FP_REGNUM:
+		  base = info->fp_offset;
+		  info->fp_offset += m * di;
+		  break;
+		case NDS32_SP_REGNUM:
+		  base = info->sp_offset;
+		  info->sp_offset += m * di;
+		  break;
+		default:
+		  /* sorry, only ra==sp || ra==fp is handled */
+		  break;
+		}
+	      if (base == ~1 + 1)
                          ^^^^^^^ ??

+		break;	  /* skip */
+
+	      if (insn & (1 << 0x4))	/* b:0, a:1 */
+		base += 4 * di;		/* a: use Ra+4 (for i),
+					      or Ra-4 (for d) */
+	      /* else base = base;	b use Ra */
+
+	      /* Cole 3th Nov. 2010
+		 We should consider both increasing and decreasing case.
+
+		 Either case stores registers in the same order.
+		 To simplify the code (yes, the loops),
+		 I used the same pushing order, but from different side.  */
+
+	      if (di == 1)		/* Increasing.  */
+		base += (rn * 4 - 4);
+	      /* else, in des case, we already are on the top */
+
+	      for (i = 0; i < 4; i++)
+		{
+		  if (enable4 & (1 << enb4map[aligned][i]))
+		    {
+		      info->saved_regs[NDS32_SP_REGNUM -
+				       (enb4map[aligned][i])].addr = base;
+		      base -= 4;
+		    }
+		}
+
+	      /* Skip re == rb == sp > fp.  */
+	      for (i = re; i >= rb && rb < NDS32_FP_REGNUM; i--)
+		{
+		  info->saved_regs[i].addr = base;
+		  base -= 4;
+		}
+
+	      continue;
+	    }
+	  /* swi $lp, [$sp + (imm15s << 2)] */
+	  /* We must check if $rt is $lp to determine it is
+	     in prologue or not.  */
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI, REG_LP, REG_FP, 0))
+	    {
+	      int imm15s;
+
+	      /* swi $lp, [$sp + (imm15s<<2)] */
+	      imm15s = N32_IMM15S (insn);
+	      info->saved_regs[NDS32_LP_REGNUM].addr = info->sp_offset
+						       + (imm15s << 2);
+	      continue;
+	    }
+	  /* swi.bi $rt, [$sp], (imm15s << 2) */
+	  if (CHOP_BITS (insn, 15) == N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0))
+	    {
+	      unsigned int rt5 = 0;
+	      unsigned int ra5 = 0;
+	      int imm15s = 0;
+	      rt5 = N32_RT5 (insn);
+	      ra5 = N32_RA5 (insn);
+	      imm15s = N32_IMM15S (insn);
+
+	      if (ra5 == NDS32_SP_REGNUM)
+		{
+		  info->saved_regs[rt5].addr = info->sp_offset;
+		  info->sp_offset += (imm15s << 2);
+		}
+	      else if (ra5 == NDS32_FP_REGNUM)
+		{
+		  info->saved_regs[rt5].addr = info->fp_offset;
+		  info->fp_offset += (imm15s << 2);
+		}
+	      continue;
+	    }
+
+	  if (N32_OP6 (insn) == N32_OP6_COP && N32_COP_CP (insn) == 0
+	      && (N32_COP_SUB (insn) == N32_FPU_FSS
+		  || N32_COP_SUB (insn) == N32_FPU_FSD)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* CP shoud be CP0 */
+	      /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */
+	      continue;
+	    }
+
+	  /* fssi $fst, [$ra + (imm12s << 2)]
+	     fssi.bi $fst, [$ra], (imm12s << 2)
+	     fsdi $fdt, [$ra + (imm12s << 2)]
+	     fsdi.bi $fdt, [$ra], (imm12s << 2) */
+	  if ((N32_OP6 (insn) == N32_OP6_SWC || N32_OP6 (insn) == N32_OP6_SDC)
+	      && (N32_RA5 (insn) == REG_SP || N32_RA5 (insn) == REG_FP))
+	    {
+	      /* fssi and fsdi have the same form.  */
+	      /* Only .bi form should be handled to adjust reg.  */
+	      unsigned int ra5 = 0;
+	      unsigned int fs5 = 0;
+	      int imm12s = 0;
+
+	      fs5 = N32_RT5 (insn);
+	      ra5 = N32_RA5 (insn);
+	      imm12s = N32_IMM12S (insn);
+
+	      if (imm12s & 0x800)
+		imm12s = (imm12s - (0x800 << 1));
+
+	      switch (ra5)
+		{
+		case NDS32_FP_REGNUM:
+		  info->fp_offset += (imm12s << 2);
+		  break;
+		case NDS32_SP_REGNUM:
+		  info->sp_offset += (imm12s << 2);
+		  break;
+		}
+
+	      continue;
+	    }
+
+	  /* TODO: Handle mfsr and addi for interrupt handlers.  */

Need to handle mfsr and addi now?

+	  break;
+	}
+      else
+	{
+	  /* 16-bit instruction */
+	  pc += 2;
+	  insn >>= 16;
+
+	  /* 1. If the instruction is j/b, then we stop
+		i.e., OP starts with 10, and beqzs8, bnezs8.
+	     2. If the operations will change sp/fp or based on sp/fp,
+		then we are in the prologue.
+	     3. If we don't know what's it, then stop.  */
+
+	  if (__GF (insn, 13, 2) == 2)
+	    {
+	      /* These are all branch instructions.  */
+	      pc -= 2;
+	      break;
+	    }
+	  else if (__GF (insn, 9, 6) == 0x34)
+	    {
+	      /* beqzs8, bnezs8 */
+	      pc -= 2;
+	      break;
+	    }
+
+	  if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
+	    {
+	      /* addi10s */
+	      info->sp_offset += N16_IMM10S (insn);
+	      continue;
+	    }
+
+	  if (__GF (insn, 7, 8) == N16_T25_PUSH25)
+	    {
+	      /* push25 */
+	      int imm8u = (insn & 0x1f) << 3;
+	      int re = ((insn & 0x60) >> 5) & 0x3;
+	      int res[] = {6, 8, 10, 14};
+	      int m[] = {4, 6, 8, 12};
+	      LONGEST base = info->sp_offset - 4;
+
+	      /* Operation 1 - smw.adm R6, [sp], Re, #0xe */
+	      info->saved_regs[NDS32_LP_REGNUM].addr = info->sp_offset - 0x4;
+	      info->saved_regs[NDS32_GP_REGNUM].addr = info->sp_offset - 0x8;
+	      info->saved_regs[NDS32_FP_REGNUM].addr = info->sp_offset - 0xC;
+	      info->sp_offset -= m[re] * 4;
+
+	      switch (re)
+		{
+		  case 3:
+		    info->saved_regs[NDS32_R0_REGNUM + 14].addr = info->sp_offset + 0x20;
+		    info->saved_regs[NDS32_R0_REGNUM + 13].addr = info->sp_offset + 0x1C;
+		    info->saved_regs[NDS32_R0_REGNUM + 12].addr = info->sp_offset + 0x18;
+		    info->saved_regs[NDS32_R0_REGNUM + 11].addr = info->sp_offset + 0x14;
+		  case 2:
+		    info->saved_regs[NDS32_R0_REGNUM + 10].addr = info->sp_offset + 0x10;
+		    info->saved_regs[NDS32_R0_REGNUM + 9].addr = info->sp_offset + 0xC;
+		  case 1:
+		    info->saved_regs[NDS32_R0_REGNUM + 8].addr = info->sp_offset + 0x8;
+		    info->saved_regs[NDS32_R0_REGNUM + 7].addr = info->sp_offset + 0x4;
+		  case 0:
+		    info->saved_regs[NDS32_R0_REGNUM + 6].addr = info->sp_offset;
+		}
+
+	      /* Operation 2 - sp = sp - imm5u<<3 */
+	      info->sp_offset -= imm8u;
+
+	      /* Operation 3 - if (Re >= 1) R8 = concat (PC(31,2), 2`b0) */
+	      continue;
+	    }
+
+	  /* mov55 fp, sp */
+	  if (insn == N16_TYPE55 (MOV55, REG_FP, REG_SP))
+	    {
+		info->fp_offset = info->sp_offset;
+		info->use_frame = 1;
+		continue;
+	    }
+	  /* swi450 */
+	  switch (insn & ~__MF (-1, 5, 4))
+	    {
+	      case N16_TYPE45 (SWI450, 0, REG_SP):
+	      case N16_TYPE45 (SWI450, 0, REG_FP):
+		break;
+	    }
+	  /* swi37 - implied fp */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  /* swi37sp - implied */
+	  if (__GF (insn, 11, 4) == N16_T37_XWI37SP
+	      && (insn & __BIT (7)))
+	    continue;
+
+	  break;
+	  }
+    }
+
+  info->size = -info->sp_offset;
+  /* Compute the previous frame's stack pointer (which is also the
+     frame's ID's stack address), and this frame's base pointer.
+
+     Assume that the FP is this frame's SP but with that pushed
+     stack space added back.  */
+  next_base = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
+  prev_sp = next_base + info->size;
+  fp_base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
+  if (info->use_frame && fp_base > 0)
+    {
+      /* Try to use FP if possible. */
+      prev_sp = fp_base - info->fp_offset;
+    }
+
+  /* Convert that SP/BASE into real addresses.  */
+  info->prev_sp = prev_sp;
+  info->base = next_base;
+
+  /* Adjust all the saved registers so that they contain addresses and
+     not offsets.  */
+  for (i = 0; i < gdbarch_num_regs (gdbarch) - 1; i++)
+    {
+      if (trad_frame_addr_p (info->saved_regs, i))
+	{
+	  info->saved_regs[i].addr = info->prev_sp + info->saved_regs[i].addr;
+	}
+    }
+
+  /* The previous frame's SP needed to be computed.
+     Save the computed value.  */
+  trad_frame_set_value (info->saved_regs, NDS32_SP_REGNUM, prev_sp);
+
+  return info;
+}
+


+/* Implement the gdbarch_skip_permanent_breakpoint method.  */
+
+static void
+nds32_skip_permanent_breakpoint (struct regcache *regcache)
+{
+  int insn;
+  CORE_ADDR current_pc = regcache_read_pc (regcache);
+
+  /* On nds32, breakpoint may be BREAK or BREAK16.  */
+  insn = read_memory_unsigned_integer (current_pc, 4, BFD_ENDIAN_BIG);
+
+  /* FIXME: Review this code.  */
+  if (N32_OP6 (insn) == N32_OP6_MISC && N32_SUB5 (insn) == N32_MISC_BREAK)
+    current_pc += 4;
+  else if (__GF (insn, 9, 6) == 35 && N16_IMM9U (insn) < 32)
+    current_pc += 2;
+  else
+    return;

Looks like there are two kinds of breakpoint instructions, 16-bit one and 32-bit one. It is inconsistent with nds32_breakpoint_from_pc, where only 16-bit breakpoint instruction is used.

+
+  regcache_write_pc (regcache, current_pc);
+}
+

+
+/* Implement the gdbarch_push_dummy_call method.  */
+
+static CORE_ADDR
+nds32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+		       struct regcache *regcache, CORE_ADDR bp_addr,
+		       int nargs, struct value **args, CORE_ADDR sp,
+		       int struct_return, CORE_ADDR struct_addr)
+{
+  const int REND = 6;		/* Max arguments number.  */
+  int goff = 0;			/* Current gpr for argument.  */
+  int foff = 0;			/* Currnet gpr for argument.  */
+  int soff = 0;			/* Current stack offset.  */
+  int i;
+  struct type *type;
+  enum type_code typecode;
+  CORE_ADDR regval;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int use_spill;
+  int use_fpr;
+  int fs0_regnum = -1, fd0_regnum = -1;
+
+  switch (tdep->nds32_abi)
+    {
+    case NDS32_ABI_V2:
+    case NDS32_ABI_V2FP:
+      use_spill = FALSE;
+      break;
+    default:
+      use_spill = TRUE;
+    break;
+  }
+
+  /* Use FP registers for calling iff when ABI==V2FP.  */
+  use_fpr = (tdep->nds32_abi == NDS32_ABI_V2FP);
+  if (use_fpr)
+    {
+      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0",
strlen ("fs0"));
+      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0",
strlen ("fd0"));
+    }
+
+  /* Set the return address.  For the nds32, the return breakpoint is
+     always at BP_ADDR.  */
+  regcache_cooked_write_unsigned (regcache, NDS32_LP_REGNUM, bp_addr);
+
+  /* If STRUCT_RETURN is true, then the struct return address (in
+     STRUCT_ADDR) will consume the first argument-passing register.
+     Both adjust the register count and store that value.  */
+  if (struct_return)
+    {
+      regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, struct_addr);
+      goff++;
+    }
+
+  /* Now make sure there's space on the stack */
+  for (i = 0; i < nargs; i++)
+    {
+      struct type *type = value_type (args[i]);
+      int align = nds32_type_align (type);
+
+      gdb_assert (align != 0);
+      sp -= TYPE_LENGTH (type);
+      if (align)
+	{
+	  /* FIXME: Handle empty structure?  */
+	  sp &= ~(align - 1);
+	}
+    }
+
+  /* Stack must be 8-byte aligned.  */
+  sp = sp & ~7;

I prefer using align_down (sp, 8) here.

+
+/* Given a return value in `regbuf' with a type `valtype',
+   extract and copy its value into `valbuf'.  */

The comment is inconsistent with the parameters of this functions.

+
+static void
+nds32_extract_return_value (struct type *type, struct regcache *regcache,
+			    gdb_byte *readbuf)
+{
+  int len = TYPE_LENGTH (type);
+  int typecode = TYPE_CODE (type);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int i;
+  int fs0_regnum, fd0_regnum;
+  int use_fpr;
+
+  use_fpr = (tdep->nds32_abi == NDS32_ABI_V2FP);
+
+  /* TODO: one-float, one-double is special case in V2FP.
+     Passed in FS/FD */
+  gdb_assert (TYPE_LENGTH (type) <= 8);
+  if (nds32_float_in_struct (type))
+    typecode = TYPE_CODE_FLT;
+
+  if (typecode == TYPE_CODE_FLT && use_fpr)
+    {
+      fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0",
strlen ("fs0"));
+      fd0_regnum = user_reg_map_name_to_regnum (gdbarch, "fd0",
strlen ("fd0"));
+

Looks your mailer wrap up your patch, so that it can't be applied cleanly.

+
+static int
+nds32_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;
+    }
+
+#if 0
+    /* TODO: extend the sniffer as following if (tdep->sigtramp_start != 0) */
+    {
+      CORE_ADDR pc = frame_pc_unwind (this_frame);
+
+      gdb_assert (tdep->sigtramp_end != 0);
+      if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end)
+	return &nds32_sigtramp_frame_unwind;
+    }
+#endif

Remove it?

+  return 0;
+}
+

+
+static int
+gdb_print_insn_nds32 (bfd_vma memaddr, disassemble_info *info)
+{
+  struct gdbarch *gdbarch = info->application_data;
+  struct obj_section * s = find_pc_section (memaddr);
+  struct cleanup *back_to;
+
+  /* Reload symtab if abfd changed.

I am sorry that I can't get the points of doing this. Can you elaborate please?

+     In case there are multiple ITB in different shared objects.  */
+  if (s == NULL || info->section != s->the_bfd_section)
+    {
+      xfree (info->symtab);
+      info->symtab = NULL;
+      info->symtab_size = 0;
+    }
+
+  if (info->symtab == NULL && s && s->the_bfd_section)
+    {
+      long storage = bfd_get_symtab_upper_bound (s->objfile->obfd);
+
+      if (storage <= 0)
+	goto done;
+
+      info->section = s->the_bfd_section;
+      info->symtab = xmalloc (storage);
+      info->symtab_size =
+	bfd_canonicalize_symtab (s->the_bfd_section->owner, info->symtab);
+    }
+
+done:
+  return print_insn_nds32 (memaddr, info);
+}
+

+
+/* Callback for "nds32 dump" command.
+
+   Dump current register and stack for debug gdb.  */
+

Do we really need this command? You can examine registers via command 'info registers', and examine stack as a piece of memory via command 'x'.

+static void
+nds32_dump_command (char *arg, int from_tty)
+{
+  ULONGEST val;
+  ULONGEST sp;
+  FILE *f_script;
+  char cmdline[512];
+  int i;
+
+  if (arg == NULL)
+    {
+      printf_unfiltered (_("Missing filename argument.\n"));
+      return;
+    }
+
+  regcache_raw_read_unsigned (get_current_regcache (), NDS32_SP_REGNUM, &sp);
+
+  sprintf (cmdline, "dump binary memory %s.stack 0x%lx 0x%lx",
+	   arg, (long) sp, ((long) sp + 1024 - 1) & ~(1024 - 1));
+  execute_command (cmdline, from_tty);
+
+  sprintf (cmdline, "%s.gdbinit", arg);
+  f_script = fopen (cmdline, "w");
+  if (f_script == NULL)
+    {
+      printf_unfiltered (_("Fail to generate dump .gdbinit."));
+      return ;
+    }
+
+  /* Gather all user registers.  */
+  for (i = 0; i <= NDS32_D1HI_REGNUM; i++)
+    {
+      regcache_raw_read_unsigned (get_current_regcache (), i, &val);
+      fprintf (f_script, "set $%s = 0x%lx\n", nds32_regnames[i], (long) val);
+    }
+
+  fprintf (f_script, "restore %s.stack binary 0x%lx\n", arg, (long) sp);
+  fclose (f_script);
+}
+
+static int
+nds32_config_int (const char *str, int def)
+{
+  int val = def;
+
+  if (getenv (str))
+    val = atoi (getenv (str));
+  if (val != def)
+    printf ("%s=%d\n", str, val);

It is not good to print in this way. If you really need to print some debug message, please add a flag "nds32_debug",

  if (nds32_debug)
    fprintf_unfiltered (gdb_stdlog, "%s = %d\n", str, val));

and add a command to contrl this flag.

See 'arm_debug' in arm-tdep.c.

+  return val;
+}
+
+static void
+nds32_load_config (struct nds32_gdb_config *config)
+{
+  config->use_cfi = nds32_config_int ("USE_CFI", 1);
+  config->use_abi = nds32_config_int ("USE_ABI", NDS32_ABI_AUTO);
+}
+
+/* Callback for "nds32" command.  */
+
+static void
+nds32_command (char *arg, int from_tty)
+{
+  printf_unfiltered (_("\"nds32\" must be followed by arguments\n"));
+}
+
+struct cmd_list_element *nds32_cmdlist;
+
+void
+_initialize_nds32_tdep (void)
+{
+  /* Internal used config for testing.  */
+  nds32_load_config (&nds32_config);
+
+  add_prefix_cmd ("nds32", no_class, nds32_command,
+		  _("Various nds32-specific commands."), &nds32_cmdlist,
+		  "nds32 ", 0, &cmdlist);
+
+  add_cmd ("dump", class_files, nds32_dump_command,
+	   _("dump stack and GPRs for debugging"), &nds32_cmdlist);

Not sure the command is necessary. If it is, don't forget to update gdb/doc/gdb.texinfo about the new command.

+
+  nds32_init_remote_cmds ();
+
+  /* Initialize gdbarch.  */
+  register_gdbarch_init (bfd_arch_nds32, nds32_gdbarch_init);
+
+  /* Following are NDS32 specific commands.  */
+
+  nds32_init_reggroups ();
+
+  register_remote_support_xml ("nds32");
+}
diff --git a/gdb/nds32-tdep.h b/gdb/nds32-tdep.h
new file mode 100644
index 0000000..2a71a14
--- /dev/null
+++ b/gdb/nds32-tdep.h
@@ -0,0 +1,127 @@
+/* Common target dependent code for GDB on nds32 systems.
+

+
+/* All the possible NDS32 ABIs.  They must be consistent with elf/nds32.h.  */
+enum nds32_abi
+{
+  NDS32_ABI_V0 = 0,
+  NDS32_ABI_V1,
+  NDS32_ABI_V2,
+  NDS32_ABI_V2FP,
+  NDS32_ABI_AABI,
+  NDS32_ABI_END,
+  NDS32_ABI_BEGIN = NDS32_ABI_V0,
+  /* ABI flag is only 4-bits long.  */
+  NDS32_ABI_AUTO = 0xFFFFFFFF
+};

The ABI stuff should go to binutils, and GDB only uses them, right?

+
+/* ----------------------------------------------
+   31   28 27                 8 7   4 3       0
+   ----------------------------------------------
+   | ARCH | CONFUGURAION FIELD | ABI | VERSION  |
+   ---------------------------------------------- */

What does this comment mean?

The last but not least, the binutils patch hasn't go in yet, so it is pity that I can't build GDB with you patches for nds32 target.

You also need a news entry in gdb/NEWS about this new port. Open gdb/NEWS, and then you will know how to add one entry for nds32 port :)

--
Yao (éå)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]