This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH 1/5] Code for nds32 target
- From: Yao Qi <yao at codesourcery dot com>
- To: Wei-cheng Wang <cole945 at gmail dot com>
- Cc: <gdb-patches at sourceware dot org>
- Date: Wed, 10 Jul 2013 13:37:50 +0800
- Subject: Re: [PATCH 1/5] Code for nds32 target
- References: <CAPmZyH4TFFOvyis+so2=sd0oNg3-m0Kj1H-vske=WyK57TLqVQ at mail dot gmail dot com>
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 (éå)