From: Yao Qi <yao@codesourcery.com>
To: Wei-cheng Wang <cole945@gmail.com>
Cc: <gdb-patches@sourceware.org>
Subject: Re: [PATCH 1/5] Code for nds32 target
Date: Wed, 10 Jul 2013 05:38:00 -0000 [thread overview]
Message-ID: <51DCF32E.9020303@codesourcery.com> (raw)
In-Reply-To: <CAPmZyH4TFFOvyis+so2=sd0oNg3-m0Kj1H-vske=WyK57TLqVQ@mail.gmail.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 (é½å°§)
next prev parent reply other threads:[~2013-07-10 5:38 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-08 9:28 Wei-cheng Wang
2013-07-08 23:58 ` Joseph S. Myers
2013-07-09 16:18 ` Wei-cheng Wang
2013-07-09 4:10 ` Yao Qi
2013-07-09 18:23 ` Wei-cheng Wang
2013-07-25 2:35 ` Yao Qi
2013-07-10 5:38 ` Yao Qi [this message]
2013-07-11 14:06 ` Wei-cheng Wang
2013-07-11 14:26 ` Wei-cheng Wang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51DCF32E.9020303@codesourcery.com \
--to=yao@codesourcery.com \
--cc=cole945@gmail.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox