📄 arm_stub.c
字号:
if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! if (ins & 0x01000000) { // Add/subtract offset before if ((ins & 0x02000000) == 0) { // Immediate offset if (ins & 0x00800000) { // Add offset Rn += (ins & 0x00000FFF); } else { // Subtract offset Rn -= (ins & 0x00000FFF); } } else { // Offset is in a register if (ins & 0x00800000) { // Add offset Rn += RmShifted(ins & 0x00000FFF); } else { // Subtract offset Rn -= RmShifted(ins & 0x00000FFF); } } } return ((unsigned long *)*(unsigned long *)Rn); } } } return (pc+1); case 0x2: // Branch, LDM/STM if ((ins & 0x02000000) == 0) { // LDM/STM if ((ins & 0x00100000) == 0) { // STM return (pc+1); } else { // LDM if ((ins & 0x00008000) == 0) { // PC not in list return (pc+1); } else { Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16); if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! offset = ins & 0x0000FFFF; reg_count = 0; for (i = 0; i < 15; i++) { if (offset & (1<<i)) reg_count++; } if (ins & 0x00800000) { // Add offset Rn += reg_count*4; } else { // Subtract offset Rn -= 4; } return ((unsigned long *)*(unsigned long *)Rn); } } } else { // Branch if (ins_will_execute(ins)) { offset = (ins & 0x00FFFFFF) << 2; if (ins & 0x00800000) offset |= 0xFC000000; // sign extend new_pc = (unsigned long)(pc+2) + offset; // If its BLX, make new_pc a thumb address. if ((ins & 0xFE000000) == 0xFA000000) { if ((ins & 0x01000000) == 0x01000000) new_pc |= 2; new_pc = MAKE_THUMB_ADDR(new_pc); } return ((unsigned long *)new_pc); } else { // Falls through return (pc+1); } } case 0x3: // Coprocessor & SWI return (pc+1); default: // Never reached - but fixes compiler warning. return 0; }}// FIXME: target_ins also needs to check for CPSR/THUMB being set and// set the thumb bit accordingly.static unsigned longtarget_thumb_ins(unsigned long pc, unsigned short ins){ unsigned long new_pc = MAKE_THUMB_ADDR(pc+2); // default is fall-through // to next thumb instruction unsigned long offset, arm_ins, sp; int i; switch ((ins & 0xf000) >> 12) { case 0x4: // Check for BX or BLX if ((ins & 0xff07) == 0x4700) new_pc = (unsigned long)get_register((ins & 0x00078) >> 3); break; case 0xb: // push/pop // Look for "pop {...,pc}" if ((ins & 0xf00) == 0xd00) { // find PC sp = (unsigned long)get_register(SP); for (offset = i = 0; i < 8; i++) if (ins & (1 << i)) offset += 4; new_pc = *(cyg_uint32 *)(sp + offset); if (!v5T_semantics()) new_pc = MAKE_THUMB_ADDR(new_pc); } break; case 0xd: // Bcc // Use ARM function to check condition arm_ins = ((unsigned long)(ins & 0x0f00)) << 20; if (ins_will_execute(arm_ins)) { offset = (ins & 0x00FF) << 1; if (ins & 0x0080) offset |= 0xFFFFFE00; // sign extend new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset); } break; case 0xe: // check for B if ((ins & 0x0800) == 0) { offset = (ins & 0x07FF) << 1; if (ins & 0x0400) offset |= 0xFFFFF800; // sign extend new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset); } break; case 0xf: // BL/BLX (4byte instruction!) // First instruction (bit 11 == 0) holds top-part of offset if ((ins & 0x0800) == 0) { offset = (ins & 0x07FF) << 12; if (ins & 0x0400) offset |= 0xFF800000; // sign extend // Get second instruction // Second instruction (bit 11 == 1) holds bottom-part of offset ins = *(unsigned short*)(pc+2); // Check for BL/BLX if ((ins & 0xE800) == 0xE800) { offset |= (ins & 0x07ff) << 1; new_pc = (unsigned long)(pc+4) + offset; // If its BLX, force a full word alignment // Otherwise, its a thumb address. if (!(ins & 0x1000)) new_pc &= ~3; else new_pc = MAKE_THUMB_ADDR(new_pc); } } break; } return new_pc;}void __single_step (void){ unsigned long pc = get_register(PC); unsigned long cpsr = get_register(PS); // Calculate address of next instruction to be executed if (cpsr & CPSR_THUMB_ENABLE) { // thumb ss_saved_pc = target_thumb_ins(pc, *(unsigned short*)pc); } else { // ARM unsigned long curins = *(unsigned long*)pc; if (ins_will_execute(curins)) { // Decode instruction to decide what the next PC will be ss_saved_pc = (unsigned long) target_ins((unsigned long*)pc, curins); } else { // The current instruction will not execute (the conditions // don't hold) ss_saved_pc = pc+4; } } // Set breakpoint according to type if (IS_THUMB_ADDR(ss_saved_pc)) { // Thumb instruction unsigned long t_pc = UNMAKE_THUMB_ADDR(ss_saved_pc); ss_saved_thumb_instr = *(unsigned short*)t_pc; *(unsigned short*)t_pc = HAL_BREAKINST_THUMB; } else { // ARM instruction ss_saved_instr = *(unsigned long*)ss_saved_pc; *(unsigned long*)ss_saved_pc = HAL_BREAKINST_ARM; }}/* Clear the single-step state. */void __clear_single_step (void){ if (ss_saved_pc != 0) { // Restore instruction according to type if (IS_THUMB_ADDR(ss_saved_pc)) { // Thumb instruction unsigned long t_pc = UNMAKE_THUMB_ADDR(ss_saved_pc); *(unsigned short*)t_pc = ss_saved_thumb_instr; } else { // ARM instruction *(unsigned long*)ss_saved_pc = ss_saved_instr; } ss_saved_pc = 0; }}void __install_breakpoints (void){#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0) /* Install the breakpoints in the breakpoint list */ __install_breakpoint_list();#endif}void __clear_breakpoints (void){#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0) __clear_breakpoint_list();#endif}/* If the breakpoint we hit is in the breakpoint() instruction, return a non-zero value. */int__is_breakpoint_function (){ return get_register (PC) == (target_register_t)&_breakinst;}/* Skip the current instruction. Since this is only called by the stub when the PC points to a breakpoint or trap instruction, we can safely just skip 4. */void __skipinst (void){ unsigned long pc = get_register(PC); unsigned long cpsr = get_register(PS); if (cpsr & CPSR_THUMB_ENABLE) pc += 2; else pc += 4; put_register(PC, pc);}//-----------------------------------------------------------------------// Thumb-aware GDB interrupt handler.// This is a brute-force replacement of the ones in hal_stub.c. Need to// find a better way of handling it... Maybe... Probably only ARM/thumb// that is this weird.typedef struct{ cyg_uint32 targetAddr; union { cyg_uint32 arm_instr; cyg_uint16 thumb_instr; } savedInstr;} instrBuffer;static instrBuffer break_buffer;volatile int cyg_hal_gdb_running_step = 0;// This function is passed thumb/arm information about the PC address// in bit 0. This information is passed on to the break_buffer.void cyg_hal_gdb_place_break (target_register_t pc){ // Clear flag that we Continued instead of Stepping cyg_hal_gdb_running_step = 0; if (0 == break_buffer.targetAddr) { // Setting a breakpoint in Thumb or ARM code? if (IS_THUMB_ADDR(pc)) { break_buffer.targetAddr = (cyg_uint32)pc; pc = UNMAKE_THUMB_ADDR(pc); break_buffer.savedInstr.thumb_instr = *(cyg_uint16*)pc; *(cyg_uint16*)pc = HAL_BREAKINST_THUMB; } else { break_buffer.targetAddr = (cyg_uint32)pc; break_buffer.savedInstr.arm_instr = *(cyg_uint32*)pc; *(cyg_uint32*)pc = HAL_BREAKINST_ARM; } __data_cache(CACHE_FLUSH); __instruction_cache(CACHE_FLUSH); }}int cyg_hal_gdb_remove_break (target_register_t pc){ if ( cyg_hal_gdb_running_step ) return 0; // Do not remove the break: we must hit it! if (pc == UNMAKE_THUMB_ADDR(break_buffer.targetAddr)) { if (IS_THUMB_ADDR(break_buffer.targetAddr)) { *(cyg_uint16*)pc = break_buffer.savedInstr.thumb_instr; } else { *(cyg_uint32*)pc = break_buffer.savedInstr.arm_instr; } break_buffer.targetAddr = 0; __data_cache(CACHE_FLUSH); __instruction_cache(CACHE_FLUSH); return 1; } return 0;}void cyg_hal_gdb_interrupt (target_register_t pc){ // Clear flag that we Continued instead of Stepping cyg_hal_gdb_running_step = 0; // and override existing break? So that a ^C takes effect... if (0 != break_buffer.targetAddr) cyg_hal_gdb_remove_break( break_buffer.targetAddr ); if (0 == break_buffer.targetAddr) { cyg_uint32 cpsr = get_register(PS); if (cpsr & CPSR_THUMB_ENABLE) { break_buffer.targetAddr = MAKE_THUMB_ADDR((cyg_uint32)pc); break_buffer.savedInstr.thumb_instr = *(cyg_uint16*)pc; *(cyg_uint16*)pc = HAL_BREAKINST_THUMB; } else { break_buffer.targetAddr = (cyg_uint32)pc; break_buffer.savedInstr.arm_instr = *(cyg_uint32*)pc; *(cyg_uint32*)pc = HAL_BREAKINST_ARM; } __data_cache(CACHE_FLUSH); __instruction_cache(CACHE_FLUSH); }}intcyg_hal_gdb_break_is_set (void){ if (0 != break_buffer.targetAddr) { return 1; } return 0;}#ifdef CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT#define ICE_THREAD_KEY0 0xDEAD0001#define ICE_THREAD_KEY1 0xDEAD0002#define ICE_THREAD_INBUFSIZ 2048#define ICE_THREAD_OUTBUFSIZ 2048#define ICE_THREAD_STACKSIZE 4096static cyg_uint8 ice_thread_inbuf[ICE_THREAD_INBUFSIZ];static cyg_uint8 ice_thread_outbuf[ICE_THREAD_OUTBUFSIZ];static cyg_uint8 ice_thread_stack[ICE_THREAD_STACKSIZE];static void ice_thread_proc(void);struct { cyg_uint32 _key0; // Must be ICE_KEY0 cyg_uint8 *in_buffer; cyg_int32 in_buffer_size; cyg_uint8 *out_buffer; cyg_int32 out_buffer_size; cyg_uint8 *stack; cyg_int32 stack_size; void (*fun)(void); cyg_uint32 _key1; // Must be ICE_KEY1} hal_arm_ice_thread_handler = { ICE_THREAD_KEY0, ice_thread_inbuf, ICE_THREAD_INBUFSIZ, ice_thread_outbuf, ICE_THREAD_OUTBUFSIZ, ice_thread_stack, ICE_THREAD_STACKSIZE, ice_thread_proc, ICE_THREAD_KEY1,};static intice_thread_query(void){ switch (ice_thread_inbuf[1]) { case 'L': // get thread list stub_pkt_getthreadlist(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf)); break; case 'P': // thread or process information stub_pkt_getthreadinfo(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf)); break; case 'C': // current thread stub_pkt_currthread(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf)); break; default: return 0; } return 1;}static intice_thread_set(void){ return 0;}static voidice_thread_proc(void){ switch (ice_thread_inbuf[0]) { case 'g': // Fetch thread registers stub_format_registers(ice_thread_outbuf); return; case 'P': // Update a single register case 'G': // Update all registers stub_update_registers(ice_thread_inbuf, ice_thread_outbuf); return; case 'H': // Thread set/query stub_pkt_changethread(&ice_thread_inbuf[1], ice_thread_outbuf, sizeof(ice_thread_outbuf)); return; case 'q': // Thread queries if (ice_thread_query()) return; break; case 'Q': // Thread set operations if (ice_thread_set()) return; break; case 'T': // Thread alive? stub_pkt_thread_alive(&ice_thread_inbuf[1], ice_thread_outbuf, sizeof(ice_thread_outbuf)); return; default: } strcpy(ice_thread_outbuf, "ENN"); // Dunno}#endif // CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -