📄 singlestep.c
字号:
//==========================================================================//// singlestep.c//// ARM(R) specific single-step support.////==========================================================================//####COPYRIGHTBEGIN####// // ------------------------------------------- // The contents of this file are subject to the Red Hat eCos Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.redhat.com/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations under // the License. // // The Original Code is eCos - Embedded Configurable Operating System, // released September 30, 1998. // // The Initial Developer of the Original Code is Red Hat. // Portions created by Red Hat are // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. // All Rights Reserved. // ------------------------------------------- // //####COPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): // Contributors: gthomas// Date: 1999-10-20// Purpose: ARM(R) specific single-step support. // Description: ARM is a Registered Trademark of Advanced RISC Machines Limited.// Other Brands and Trademarks are the property of their// respective owners.////####DESCRIPTIONEND####////=========================================================================#include <stdlib.h>#include <bsp/bsp.h>#include <bsp/cpu.h>#include "insn.h"#define DEBUG_SINGLESTEP 0#define DEBUG_SINGLESTEP_VERBOSE 0/* * Structure to hold opcodes hoisted when breakpoints are * set for single-stepping or async interruption. */struct _bp_save { unsigned long *addr; unsigned long opcode;};#define NUM_BREAKS_SAVED 2static struct _bp_save _breaks[NUM_BREAKS_SAVED];/* * Insert a breakpoint at 'pc' using first available * _bp_save struct. */static voidinsert_ss_break(unsigned long *pc){ struct _bp_save *p = _breaks; union arm_insn inst; if (p->addr && (++p)->addr) return; /* * We can't set a breakpoint at 0 */ if (pc == 0) {#if DEBUG_SINGLESTEP bsp_printf("Setting BP at <0x%08lx>: Error\n", pc);#endif /* DEBUG_SINGLESTEP */ return; } /* * Make sure we are on a long word boundary. */ if (((unsigned long)pc & 0x3) != 0) { /* * All ARM(R) instructions are on a word boundary. * This would be invalid. Don't set a bkpt here. */#if DEBUG_SINGLESTEP bsp_printf("Setting BP at <0x%08lx>: Error\n", pc);#endif /* DEBUG_SINGLESTEP */ return; } /* * What is the current instruction */ if (bsp_memory_read(pc, 0, ARM_INST_SIZE * 8, 1, &(inst.word)) == 0) { /* * Unable to read this address, probably an invalid address. * Don't set a breakpoint here, as it will likely cause a bus error */#if DEBUG_SINGLESTEP bsp_printf("Setting BP at <0x%08lx>: Error\n", pc);#endif /* DEBUG_SINGLESTEP */ return; } if (inst.word != BREAKPOINT_INSN) { /* * Only insert a breakpoint if we haven't done so already * * We may try to insert 2 breakpoints if we to a branch to * the immediately following instruction. */#if DEBUG_SINGLESTEP bsp_printf("Setting BP at <0x%08lx>: inst <0x%08lx>\n", pc, inst.word);#endif /* DEBUG_SINGLESTEP */ p->addr = pc; p->opcode = inst.word; inst.word = BREAKPOINT_INSN; if (bsp_memory_write(pc, 0, ARM_INST_SIZE * 8, 1, &(inst.word)) == 0) { /* * Unable to write this address, probably an invalid address. * Don't set a breakpoint here, as it will likely cause a bus error */#if DEBUG_SINGLESTEP bsp_printf("Setting BP at <0x%08lx>: Error\n", pc);#endif /* DEBUG_SINGLESTEP */ return; } /* flush icache and dcache, now */ bsp_flush_dcache((void *)pc, ARM_INST_SIZE); bsp_flush_icache((void *)pc, ARM_INST_SIZE);#if DEBUG_SINGLESTEP_VERBOSE bsp_printf("Done setting BP at <0x%08lx>: inst <0x%08lx>\n", pc, *pc);#endif /* DEBUG_SINGLESTEP_VERBOSE */ }}/* * Cleanup after a singlestep. */voidbsp_singlestep_cleanup(void *registers){ struct _bp_save *p = _breaks; int i; for (i = 0; i < NUM_BREAKS_SAVED; i++, p++) { if (p->addr) { unsigned long *old_addr = p->addr;#if DEBUG_SINGLESTEP_VERBOSE bsp_printf("Remove BP at <0x%08lx>: inst <0x%08lx>\n", old_addr, *old_addr);#endif /* DEBUG_SINGLESTEP */ *(p->addr) = p->opcode; p->addr = NULL; /* flush icache and dcache, now */ bsp_flush_dcache((void *)old_addr, ARM_INST_SIZE); bsp_flush_icache((void *)old_addr, ARM_INST_SIZE);#if DEBUG_SINGLESTEP_VERBOSE bsp_printf("Done removing BP at <0x%08lx>: inst <0x%08lx>\n", old_addr, *old_addr);#endif /* DEBUG_SINGLESTEP_VERBOSE */ } }}/* * Rotate right a value by count */static unsigned long ror(unsigned long value, unsigned count){ while (count-- > 0) { if (value & 0x1) value = (value >> 1) | 0x80000000; else value = (value >> 1); } return(value);}/* * Rotate right a value by 1 with extend */static unsigned long rrx(union arm_psr sr, unsigned long value){ if (sr.psr.c_bit) value = (value >> 1) | 0x80000000; else value = (value >> 1); return(value);}/* * Logical shift left by count */static unsigned long lsl(unsigned long value, unsigned count){ value <<= count; return(value);}/* * Logical shift right by count */static unsigned long lsr(unsigned long value, unsigned count){ value >>= count; return(value); }/* * Arithmetic shift right by count */static unsigned long asr(unsigned long value, unsigned count){ unsigned long sign_ext_mask = 0; if (value & 0x80000000) { if (count >= sizeof(value)*8) sign_ext_mask = ~0; else sign_ext_mask = (~0 << (sizeof(value)*8 - count)); } value = (value >> count) | sign_ext_mask; return(value); }/* * Calculate an immediate shift operand based on input shift operand, * shift value and register address. */static unsigned long immediate_shift_operand(ex_regs_t *regs, unsigned shift_immediate, unsigned shift, unsigned Rm){ unsigned char *regs_array = (unsigned char *)regs; unsigned char *reg_ptr = ®s_array[bsp_regbyte(Rm)]; unsigned long reg_value = *((unsigned long *)(reg_ptr)); unsigned long rc = 0; BSP_ASSERT((shift_immediate >= 0) && (shift_immediate <= 0x1f)); BSP_ASSERT((shift >= 0) && (shift <= 0x3)); BSP_ASSERT((Rm >= 0) && (Rm <= 0xf)); BSP_ASSERT(bsp_regsize(Rm) == sizeof(unsigned long)); /* * According to the ARM(R) Manual, if Rm is PC then, * the value used is the address of the current instruction * plus 8 */ if (Rm == REG_PC) reg_value += 8; switch (shift) { case SHIFT_LSL: rc = lsl(reg_value, shift_immediate); break; case SHIFT_LSR: if (shift_immediate == 0) { /* * Special Case: LSR IMM(0) == 0 */ rc = 0; } else { rc = lsr(reg_value, shift_immediate); } break; case SHIFT_ASR: if (shift_immediate == 0) { /* * Special Case: ASR IMM(0) */ if (reg_value & 0x80000000) { rc = 0xFFFFFFFF; } else { rc = 0; } } else { rc = asr(reg_value, shift_immediate); } break; case SHIFT_ROR: if (shift_immediate == 0) { /* * SHIFT_RRX * Special case: ROR(0) implies RRX */ rc = rrx((union arm_psr)(unsigned long)regs->_cpsr, reg_value); } else { rc = ror(reg_value, shift_immediate); } break; default: BSP_ASSERT(0); break; } return (rc);}/* * Calculate a register shift operand based on input shift operand, * and target registers. */static unsigned long register_shift_operand(ex_regs_t *regs, unsigned Rs, unsigned shift, unsigned Rm){ unsigned char *regs_array = (unsigned char *)regs; unsigned char *Rs_ptr = ®s_array[bsp_regbyte(Rs)]; unsigned char *Rm_ptr = ®s_array[bsp_regbyte(Rm)]; unsigned long Rs_val = *((unsigned long *)(Rs_ptr)); unsigned long Rm_val = *((unsigned long *)(Rm_ptr)); unsigned long rc = 0; /* * Use only the least significant byte of Rs */ Rs_val &= 0xFF; BSP_ASSERT((Rs >= 0) && (Rs <= 0xf)); BSP_ASSERT((shift >= 0) && (shift <= 0x3)); BSP_ASSERT((Rm >= 0) && (Rm <= 0xf)); BSP_ASSERT(bsp_regsize(Rs) == sizeof(unsigned long)); BSP_ASSERT(bsp_regsize(Rm) == sizeof(unsigned long)); BSP_ASSERT((Rs_val >=0) && (Rs_val <= 0xff)); /* * According to the ARM(R) Manual, if Rm is PC then, * the value used is the address of the current instruction * plus 8 */ if (Rm == REG_PC) Rm_val += 8; switch (shift) { case SHIFT_LSL: rc = lsl(Rm_val, Rs_val); break; case SHIFT_LSR: rc = lsr(Rm_val, Rs_val); break; case SHIFT_ASR: rc = asr(Rm_val, Rs_val); break; case SHIFT_ROR: rc = ror(Rm_val, Rs_val); break; default: BSP_ASSERT(0); break; } return (rc);}/* * Calculate a branch exchange operand based on input destination register */static unsigned long branch_exchange_operand(ex_regs_t *regs, unsigned Rm){ unsigned char *regs_array = (unsigned char *)regs; unsigned char *reg_ptr = ®s_array[bsp_regbyte(Rm)]; unsigned long reg_value = *((unsigned long *)(reg_ptr)); BSP_ASSERT((Rm >= 0) && (Rm <= 0xf)); BSP_ASSERT(bsp_regsize(Rm) == sizeof(unsigned long)); /* * Clear the low-order bit */ return (reg_value & ~0x1);}/* * Handle a load to the PC */static void handle_pc_load(unsigned size, unsigned long operand){ unsigned long mem_value = 0; if (size == LS_SIZE_WORD) { if (bsp_memory_read((void*)(operand & ~0x3), 0, 32, 1, &mem_value) == 0) { /* * Unable to read the memory address. * Don't try any further. */#if DEBUG_SINGLESTEP bsp_printf("Setting BP at *(0x%08lx): Error\n", operand & ~0x3);#endif /* DEBUG_SINGLESTEP */ return; } else {#if DEBUG_SINGLESTEP bsp_printf("Setting BP at *(0x%08lx): data <0x%08lx>\n", operand & ~0x3, mem_value);#endif /* DEBUG_SINGLESTEP */ } /* * Handle rotations if required */ switch (operand & 0x3) { case 0x0: break; case 0x1: mem_value = ror(mem_value, 8); break; case 0x2: mem_value = ror(mem_value, 16); break; case 0x3: mem_value = ror(mem_value, 24); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -