From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21951 invoked by alias); 10 Jul 2013 05:38:18 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 21941 invoked by uid 89); 10 Jul 2013 05:38:17 -0000 X-Spam-SWARE-Status: No, score=-4.5 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,TW_CP,TW_EG,TW_SM autolearn=ham version=3.3.1 Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 10 Jul 2013 05:38:14 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1Uwn6R-0005i4-Hm from Yao_Qi@mentor.com ; Tue, 09 Jul 2013 22:38:11 -0700 Received: from SVR-ORW-FEM-04.mgc.mentorg.com ([147.34.97.41]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Tue, 9 Jul 2013 22:38:11 -0700 Received: from qiyao.dyndns.org (147.34.91.1) by svr-orw-fem-04.mgc.mentorg.com (147.34.97.41) with Microsoft SMTP Server id 14.2.247.3; Tue, 9 Jul 2013 22:38:08 -0700 Message-ID: <51DCF32E.9020303@codesourcery.com> Date: Wed, 10 Jul 2013 05:38:00 -0000 From: Yao Qi User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20130110 Thunderbird/17.0.2 MIME-Version: 1.0 To: Wei-cheng Wang CC: Subject: Re: [PATCH 1/5] Code for nds32 target References: In-Reply-To: Content-Type: text/plain; charset="UTF-8"; format=flowed Content-Transfer-Encoding: 8bit X-SW-Source: 2013-07/txt/msg00258.txt.bz2 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 (齐尧)