全部博文(2005)
分类:
2009-04-19 16:32:19
浅析eCos系统Redboot内置GDB功能的具体代码实现 packages/hal/common/v2_0/src/generic-stub.c packages/hal/arm/arch/v2_0/src/vectors.S|405| bl initialize_stub packages/redboot/v2_0/src/main.c|178| cyg_start(void) ==>initialize_stub() ==>set_debug_traps() ==>__install_traps() ==> // Install the standard set of trap handlers for the stub. void __install_traps (void) { // Set signal handling vector so we can treat 'C __process_signal_vec = &cyg_hal_process_signal; __process_exit_vec = &handle_exception_exit; __cleanup_vec = &handle_exception_cleanup; __init_vec = &handle_exception_init; #ifndef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this should go away #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT // Control of GDB interrupts. __interruptible_control = HAL_STUB_PLATFORM_INTERRUPTIBLE; #endif #endif // Nothing further to do, handle_exception will be called when an // exception occurs. } //==================== void cyg_start(void) { ... while (true) { if (prompt) { diag_printf("RedBoot > "); prompt = false; } ... if (res == _GETS_GDB) {//从com口获得了'$'符号,进入GDB模式 int dbgchan; hal_virtual_comm_table_t *__chan; int i; // Special case of '$' - need to start GDB protocol gdb_active = true; // Mask interrupts on all channels // 关闭所有通道的中断 for (i = 0; i < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS; i++) { CYGACC_CALL_IF_SET_CONSOLE_COMM(i); __chan = CYGACC_CALL_IF_CONSOLE_PROCS(); CYGACC_COMM_IF_CONTROL( *__chan, __COMMCTL_IRQ_DISABLE ); } CYGACC_CALL_IF_SET_CONSOLE_COMM(cur); #ifdef HAL_ARCH_PROGRAM_NEW_STACK HAL_ARCH_PROGRAM_NEW_STACK(breakpoint); #else //对于Redboot执行这里, //packages/hal/arm/arch/v2_0/src/hal_misc.c /* This function will generate a breakpoint exception. It is used at the beginning of a program to sync up with a debugger and can be used otherwise as a quick means to stop program execution and "break" into the debugger. */ //void //breakpoint(void) //{ // HAL_BREAKPOINT(_breakinst); //} breakpoint(); // Get GDB stubs started, with a proper environment, etc. // 调用breakpoint();触发异常,使cpu进入undefined_instruction异常处理函数,进而执行 // exception_handler==>__handle_exception==>__process_exception_vec==>process_exception // #endif dbgchan = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); CYGACC_CALL_IF_SET_CONSOLE_COMM(dbgchan); } //==================== static int process_exception (int sigval) { int status; /* Nasty. */ if (ungot_char < 0) send_t_packet (sigval); // 与pc上运行的GDB程序建立链接 [luther.gliethttp] do { __getpacket (__remcomInBuffer); // 以阻塞方式[没有超时]读取来自GDB或者Insight的调试命令 [luther.gliethttp] status = __process_packet (__remcomInBuffer); // 处理来自GDB或者Insight的调试命令 [luther.gliethttp] } while (status == 0); if (status < 0) return 0; else return 1; } int __process_packet (char *packet) { int is_binary = 0; #if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) int is_Z = 0; #endif __remcomOutBuffer[0] = 0; switch (packet[0]) // 由PC的Insight发送过来的第1个字节数据为命令字[luther.gliethttp] { case '?': // 询问目标机停机原因 { int sigval = __computeSignal (__get_trap_number ()); __remcomOutBuffer[0] = 'S'; __remcomOutBuffer[1] = hexchars[(sigval >> 4) & 0xf]; __remcomOutBuffer[2] = hexchars[sigval & 0xf]; __remcomOutBuffer[3] = 0;// 回应的ascii类型字符串结尾0. break; } #ifdef __ECOS__ #if !defined(CYG_HAL_STARTUP_RAM) // Only for ROM based stubs #if 0 // Disable to avoid conflict with stub-breakpoint z/Z-packets case 'z': /* report IO buffer sizes so download can achieve optimal download speed */ { int i; i = __intToHex (__remcomOutBuffer, BUFMAX, 32); __remcomOutBuffer[i] = 0; break; } #endif case 'd': /* toggle debug flag */ strcpy(__remcomOutBuffer, GDB_stubs_version); break; #endif #endif // __ECOS__ case 'q': // qc,qCRC,qOffsets,qSymbol,qRcmd等信息查询 /* general query packet */ process_query (&packet[1]); break; case 'Q': /* general set packet */ process_set (&packet[1]); break; case 'p': /* return the value of a single CPU register */ case 'g': /* return the value of the CPU registers */ { stub_format_registers(&packet[0], __remcomOutBuffer); // 读取寄存器值 break; } ... case 'P': // 向全部寄存器或者指定寄存器推入GDB设置的新值[luther.gliethttp] case 'G': /* set the value of the CPU registers - return OK */ { char *in_ptr = &packet[0]; char *out_ptr = __remcomOutBuffer; stub_update_registers(in_ptr, out_ptr); break; } case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ /* Try to read %x,%x. */ { // 获取指定内存区中数据 target_register_t length; char *ptr = &packet[1]; target_addr_t addr; if (__hexToAddr (&ptr, &addr) && *ptr++ == ',' && __hexToInt (&ptr, &length)) { if (__mem2hex_safe (addr, __remcomOutBuffer, length)) break; strcpy (__remcomOutBuffer, "E03"); } else strcpy (__remcomOutBuffer, "E01"); break; } ... case 'S': case 's': /* sAA..AA Step from address AA..AA (optional) */ case 'C': case 'c': /* cAA..AA Continue at address AA..AA (optional) */ /* try to read optional parameter, pc unchanged if no parm */ { // 单步执行,在当前位置继续执行等[luther.gleithttp] char *ptr = &packet[1]; target_addr_t addr; target_register_t sigval = 0; if (packet[0] == 'C' || packet[0] == 'S') { __hexToInt (&ptr, &sigval); if (*ptr == ';') ptr++; } if (__hexToAddr (&ptr, &addr)) set_pc ((target_register_t)TARGET_ADDR_TO_PTR(addr)); // 设置PC新地址,由GDB指定 /* Need to flush the instruction cache here, as we may have deposited a breakpoint, and the icache probably has no way of knowing that a data ref to some location may have changed something that is in the instruction cache. */ #ifdef __ECOS__ __data_cache (CACHE_FLUSH) ; #endif __instruction_cache (CACHE_FLUSH) ; /* If we have a function to handle signals, call it. */ if (sigval != 0 && __process_signal_vec != NULL) { /* If 0 is returned, we either ignored the signal or invoked a user handler. Otherwise, the user program should die. */ if (! __process_signal_vec (sigval)) sigval = 0; } if (sigval != 0) { sigval = SIGKILL; /* Always nuke the program */ __kill_program (sigval); return 0; } #ifdef __ECOS__ // CASE 102327 - watchpoints fight with output, so do not step // through $O packet output routines. #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT if ( cyg_hal_gdb_break_is_set() ) { packet[0] = 'c'; // Force it to be a "continue" instead of step. cyg_hal_gdb_running_step = 1; // And tell the hal_stub... } #endif #endif /* Set machine state to force a single step. */ if (packet[0] == 's' || packet[0] == 'S') { lock_thread_scheduler (0); /* 0 == single-step */ #ifdef __ECOS__ // PR 19845 workaround: // Make sure the single-step magic affects the correct registers. _registers = ®isters[0]; #endif __single_step (); // 为单步执行命令,所以在下一个pc执行地址存入break指令,比如:*(unsigned long*)ss_saved_pc = HAL_BREAKINST_ARM;这里ss_saved_pc就是接下来需要执行的语句所在地址[luther.gliethttp] } else { lock_thread_scheduler (1); /* 1 == continue */ } #ifdef __ECOS__ /* Need to flush the data and instruction cache here, as we may have deposited a breakpoint in __single_step. */ __data_cache (CACHE_FLUSH) ; __instruction_cache (CACHE_FLUSH) ; hal_flush_output(); #endif return -1; } ... case 'B': // GDB发出设置断点命令[luther.gliethttp] /* breakpoint */ { target_register_t addr; char mode; char *ptr = &packet[1]; if (__hexToInt (&ptr, &addr) && *(ptr++) == ',') { mode = *(ptr++); if (mode == 'C') __remove_breakpoint (addr,0); // 清除断点,将old_contents中的存放的原来addr处的code机器码内容还原到addr处[luther.gliethttp] else __set_breakpoint (addr,0); // 登记断点地址,实际断点设置将在__install_breakpoints()函数中完成,所有断点地址处都将 // 被HAL_BREAKINST_ARM即0xE7FFDEFE异常中断机器码替代 strcpy (__remcomOutBuffer, "OK"); } else { strcpy (__remcomOutBuffer, "E01"); } break; } case 'b': /* bBB... Set baud rate to BB... */ { target_register_t baudrate; char *ptr = &packet[1]; if (!__hexToInt (&ptr, &baudrate)) { strcpy (__remcomOutBuffer, "B01"); break; } __putpacket ("OK"); /* Ack before changing speed */ __set_baud_rate (baudrate); // 设置debug调试串口的波特率[luther.gliethttp] break; } default: __process_target_packet (packet, __remcomOutBuffer, 300); break; } /* reply to the request */ __putpacket (__remcomOutBuffer); // 将ascii类型的字符串数据返回给pc的Insight调试器 return 0; } //==================== #ifdef __thumb__ #define HAL_BREAKINST_THUMB 0xbebe // illegal instruction currently 产生指令异常,反汇编:bebe bkpt 0x00be # define HAL_BREAKPOINT(_label_) \ asm volatile (" .code 16;" \ " .globl " #_label_ ";" \ #_label_":" \ " .short " _stringify(HAL_BREAKINST_THUMB) \ //作为代码放在ROM里,当pc执行到这里时,pc取出该HAL_BREAKINST_THUMB内容,然后执行它,因为是一条非法语句,所以将出发异常,跳转到vectors.S执行undefined_instruction ); #else // __thumb__ #define HAL_BREAKINST_ARM 0xE7FFDEFE //反汇编:e7ffdefe undefined #define HAL_BREAKPOINT(_label_) \ asm volatile (" .globl " #_label_ ";" \ #_label_":" \ " .word " _stringify(HAL_BREAKINST_ARM) \ ); //==================== packages/hal/arm/arch/v2_0/src/vectors.S ... ldr pc,.undefined_instruction // 0x04 ... .code 32 undefined_instruction: //r0-r5存储到__undef_exception_stack临时缓冲区 ldr sp,.__undef_exception_stack // get good stack stmfd sp!,{r0-r5} // save some supervisor regs mrs r1,spsr tst r1,#CPSR_THUMB_ENABLE subeq r0,lr,#4 // PC at time of interrupt (ARM) subne r0,lr,#2 // PC at time of interrupt (thumb) mov r2,#CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION mov r3,sp //r3为CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION模式下sp栈空间地址 b call_exception_handler // Dispatch an exception handler. .code 32 call_exception_handler: // // On Entry: // // r4,r5 = scratch // r3 = pointer to temp save area // r2 = vector number // r1 = exception psr // r0 = exception pc // // [r3+20]: exception r5 // [r3+16]: exception r4 // [r3+12]: exception r3 // [r3+8] : exception r2 // [r3+4] : exception r1 // [r3] : exception r0 //切换到svc模式 mrs r4,cpsr // switch to Supervisor Mode bic r4,r4,#CPSR_MODE_BITS orr r4,r4,#CPSR_SUPERVISOR_MODE msr cpsr,r4 //保存svc的sp地址,lr地址 mov r5,sp // save original svc sp mov r4,lr // and original svc lr #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS // Make sure we use the GDB stack. //使用__GDB_stack作为svc模式栈,对__GDB_stack的定义见后面[luther.gliethttp] ldr sp,.__GDB_stack //检查是不是在GDB下又出发了break异常 cmp r5,sp // already on GDB stack? bhi 10f //如果存放svc的sp数值的r5大于__GDB_stack,那么说明r5位于__startup_stack空间,之前没有位于__GDB_stack //否则说明当前位于__GDB_stack空间 ldr r4,.__GDB_stack_base //这样就覆盖了r4中存放的lr[luther.gliethttp] cmp r5,r4 movhi sp,r5 //之前svc模式就已经使用__GDB_stack了,那么接着r5存储位置继续存储 10: #endif // // r5 holds original svc sp, current sp is stack to use // r4 holds original svc lr, which must also be preserved // stmfd sp!,{r0-r2,r4,r5} // push svc_sp, svc_lr, vector, psr, pc // switch to pre-exception mode to get banked regs //切换到发生undefined_instruction异常时的cpsr模式,然后保存 //那时的r0-r12,sp,lr到__GDB_stack上[luther.gliethttp]. mov r0,sp // r0 survives mode switch mrs r2,cpsr // Save current psr for return orr r1,r1,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE bic r1,r1,#CPSR_THUMB_ENABLE msr cpsr,r1 stmfd r0!,{r8-r12,sp,lr}//保存r1中保存的spsr发生undefined_instruction异常之前的特有寄存器r8-r12,sp,lr msr cpsr,r2 // back to svc mode //更新sp数值 mov sp,r0 // update stack pointer // now save pre-exception r0-r7 on current stack //将spsr模式下的r0-r5取出来 ldmfd r3,{r0-r5} //因为spsr模式和当前模式的r0-r7是共用的,r8-r14是各个模式独有的,所以 //这里也就是保存spsr模式下的r0-r5寄存器到__GDB_stack.[luther.gliethttp] stmfd sp!,{r0-r7} //至此发生undefined_instruction异常之前模式下r0-r14寄存器们全部都已经保存到__GDB_stack上了. // SP needs fixing if exception occured in SVC mode. // The original SVC LR is still in place so that // does not need to be fixed here. ldr r1,[sp,#armreg_cpsr] /* packages/hal/arm/arch/v2_0/src/hal_mk_defs.c|91| DEFINE(armreg_cpsr, offsetof(HAL_SavedRegisters, cpsr)); typedef struct { // These are common to all saved states cyg_uint32 d[HAL_NUM_THREAD_CONTEXT_REGS] ; // Data regs (r0..r10) cyg_uint32 fp; // (r11) Frame pointer cyg_uint32 ip; // (r12) cyg_uint32 sp; // (r13) Stack pointer cyg_uint32 lr; // (r14) Link Reg cyg_uint32 pc; // (r15) PC place holder // (never used) cyg_uint32 cpsr; // Condition Reg // These are only saved for exceptions and interrupts cyg_uint32 vector; // Vector number cyg_uint32 svc_lr; // saved svc mode lr cyg_uint32 svc_sp; // saved svc mode sp } HAL_SavedRegisters; */ and r1,r1,#CPSR_MODE_BITS cmp r1,#CPSR_SUPERVISOR_MODE ldreq r1,[sp,#armreg_svcsp] streq r1,[sp,#armreg_sp] //将sp恢复到原始的发生undefined_instruction的sp数值,因为当前sp在上面 //经过ldr sp,.__GDB_stack语句之后,使用__GDB_stack作为svc模式栈,所以这里需要修改为发生异常之前的真正的svc栈值 #ifdef CYGHWR_HAL_ARM_DUMP_EXCEPTIONS mov r0,sp ldr r1,.__dump_procs ldr r2,[sp,#armreg_vector] mov lr,pc ldr pc,[r1,r2,lsl #2] #endif // call exception handler mov r0,sp //r0存放HAL_SavedRegisters结构体首地址 THUMB_MODE(r9,10) bl exception_handler //GDB异常处理函数 #ifdef CYGHWR_HAL_ARM_DUMP_EXCEPTIONS mov r0,sp bl cyg_hal_report_exception_handler_returned //打印栈信息 #endif ARM_MODE(r1,10) // // Return from exception //从这个undefined_instruction异常返回回去[luther.gliethttp] // return_from_exception: ldr r0,[sp,#armreg_cpsr] msr spsr,r0 // return to supervisor mode is simple and r1,r0,#CPSR_MODE_BITS cmp r1,#CPSR_SUPERVISOR_MODE ldmeqfd sp,{r0-r14,pc}^ // // return to other non-user modes is a little trickier // // switch to pre-exception mode and restore r8-r14 add r2,sp,#armreg_r8 mrs r1,cpsr orr r0,r0,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE bic r0,r0,#CPSR_THUMB_ENABLE msr cpsr,r0 ldmfd r2,{r8-r14} // 先恢复该模式下的r8-r14独有寄存器[luther.gliethttp] msr cpsr, r1 // back to svc mode // move sp,lr and pc for final load ldr r0,[sp,#armreg_svcsp] str r0,[sp,#armreg_r8] ldr r0,[sp,#armreg_svclr] str r0,[sp,#armreg_r9] ldr r0,[sp,#armreg_pc] str r0,[sp,#armreg_r10] // restore r0-r7,sp,lr and return from exception ldmfd sp,{r0-r7,sp,lr,pc}^ #ifdef CYGHWR_HAL_ARM_DUMP_EXCEPTIONS __dump_procs: .word 0 // placeholder for reset .word cyg_hal_report_undefined_instruction .word cyg_hal_report_software_interrupt .word cyg_hal_report_abort_prefetch .word cyg_hal_report_abort_data .word 0 // reserved #endif #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS .balign 16 __GDB_stack_base: .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE // rather than 1k .byte 0 .endr __GDB_stack: //GDB栈空间 #endif //==================== void exception_handler(HAL_SavedRegisters *regs) { // Special case handler for code which has chosen to take care // of data exceptions (i.e. code which expects them to happen) // This is common in discovery code, e.g. checking for a particular // device which may generate an exception when probing if the // device is not present if (__mem_fault_handler && regs->vector == CYGNUM_HAL_EXCEPTION_DATA_ACCESS) { regs->pc = (unsigned long)__mem_fault_handler; return; // Caught an exception inside stubs } #if defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS) && !defined(CYGPKG_CYGMON) if (++exception_level == 1) __take_over_debug_traps(); _hal_registers = regs; __handle_exception(); if (--exception_level == 0) __restore_debug_traps(); #elif defined(CYGPKG_KERNEL_EXCEPTIONS) // We should decode the vector and pass a more appropriate // value as the second argument. For now we simply pass a // pointer to the saved registers. We should also divert // breakpoint and other debug vectors into the debug stubs. cyg_hal_deliver_exception( regs->vector, (CYG_ADDRWORD)regs ); #else CYG_FAIL("Exception!!!"); #endif return; } //==================== static unsigned long *hardware_vectors = (unsigned long *)0x20; static unsigned long hold_vectors[ARM_VECTORS]; static int exception_level; static void __take_over_debug_traps(void)//初始化 { hold_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH] = hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH]; hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH] = vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH]; hold_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA] = hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA]; hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA] = vectors[CYGNUM_HAL_VECTOR_ABORT_DATA]; } //==================== void __handle_exception (void) { int sigval = 0; #ifdef TARGET_HAS_NEXT_STEP if (! __next_step_done ()) { __clear_breakpoints (); __install_breakpoints (); __single_step (); return; } #endif #ifdef __ECOS__ // We need to unpack the registers before they are accessed. //================ if (__cleanup_vec != NULL) __cleanup_vec (); //在__install_traps==>__cleanup_vec = &handle_exception_cleanup; //handle_exception_cleanup==>HAL_GET_GDB_REGISTERS(®isters[0], _hal_registers); // ==>_registers = ®isters[0]; #if defined(CYGSEM_REDBOOT_BSP_SYSCALLS) // Temporary support for gnupro bsp SWIs //================ if (__is_bsp_syscall()) //为系统调用,好像在ep9312中没有执行SYSCALL()系统调用的地方[luther.gliethttp] { sigval = hal_syscall_handler();//见后面[luther.gliethttp] if (0 == sigval) { if (__init_vec != NULL) __init_vec (); return; } } #endif #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT // Special case for GDB BREAKs. This flag is set by cyg_stub_cleanup. //================ if (cyg_hal_gdb_break) { cyg_hal_gdb_break = 0; sigval = SIGINT; } #endif // Only compute sigval if it wasn't already computed (in // hal_syscall_handler or as a result of a GDB async break) if (0 == sigval) sigval = __computeSignal (__get_trap_number ()); #else // __ECOS__ /* reply to host that an exception has occurred */ sigval = __computeSignal (__get_trap_number ()); #endif // __ECOS__ if (__is_breakpoint_function ())// 如果当前PC位于breakpoint or trap instruction,那么if成立 { #ifdef CYGPKG_CYGMON processing_breakpoint_function = 1; #endif __skipinst ();// pc+2或+4,调整pc数值,跳过当前位于breakpoint or trap instruction的语句 } else { #ifdef CYGPKG_CYGMON processing_breakpoint_function = 0; #endif } #ifndef __ECOS__ if (__cleanup_vec != NULL) __cleanup_vec (); //在__install_traps==>__cleanup_vec = &handle_exception_cleanup; //handle_exception_cleanup==>HAL_GET_GDB_REGISTERS(®isters[0], _hal_registers); // ==>_registers = ®isters[0]; #endif // !__ECOS__ __clear_breakpoints (); /* Undo effect of previous single step. */ unlock_thread_scheduler (); __clear_single_step (); #ifdef __ECOS__ /* Need to flush the data and instruction cache here, as we may have removed a breakpoint in __single_step - and we may be sharing some code with the application! */ __data_cache (CACHE_FLUSH) ; __instruction_cache (CACHE_FLUSH) ; #endif #ifdef SIGSYSCALL if (sigval == SIGSYSCALL) { int val; /* Do the skipinst FIRST. */ #ifndef SYSCALL_PC_AFTER_INST __skipinst (); #endif val = __process_syscall_vec (__get_syscall_num ()); if (val < 0) sigval = -val; else sigval = 0; } #endif /* Indirect function call to stub, cygmon monitor or other */ if (sigval != 0) { while (__process_exception_vec (sigval)) { /* Empty! */ } } __install_breakpoints (); // 见后面,将断点指令存入断点地址处[luther.gliethttp] if (__init_vec != NULL) __init_vec (); // 将GDB寄存器中的数据恢复到_hal_registers,也就是reti中断返回时将要使用到的r0-r15内容,然后打开debug串口的IRQ中断[luther.gliethttp] } //==================== 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 __install_breakpoint_list (void) { struct breakpoint_list *l = breakpoint_list; while (l != NULL) { if (! l->in_memory) { int len = sizeof (l->old_contents); if (__read_mem_safe (&l->old_contents[0], (void*)l->addr, len) == len) // 将地址l->addr中code机器码保存到l->old_contents中[luther.gliethttp] { if (__write_mem_safe (HAL_BREAKINST_ADDR(l->length),// 将undefined_instruction存入断点地址处,这样执行到断点处之后,将触发cpu异常,跳致undefined_instruction处理函数进一步处理该异常[luther.gliethttp] /* #define HAL_BREAKINST_ADDR(x) (((x)==2)? \ ((void*)&__thumb_breakinst) : \ ((void*)&__arm_breakinst)) cyg_uint32 __arm_breakinst = HAL_BREAKINST_ARM; cyg_uint16 __thumb_breakinst = HAL_BREAKINST_THUMB; #define HAL_BREAKINST_ARM 0xE7FFDEFE #define HAL_BREAKINST_THUMB 0xbebe // illegal instruction currently */ (void*)l->addr, l->length) == l->length) { l->in_memory = 1; } } } l = l->next; } #if defined(HAL_STUB_HW_BREAKPOINT_LIST_SIZE) && (HAL_STUB_HW_BREAKPOINT_LIST_SIZE > 0) __install_hw_breakpoint_list(); #endif #if defined(HAL_STUB_HW_WATCHPOINT_LIST_SIZE) && (HAL_STUB_HW_WATCHPOINT_LIST_SIZE > 0) __install_hw_watchpoint_list(); #endif HAL_ICACHE_SYNC(); } //==================== __install_traps ==>__cleanup_vec = &handle_exception_cleanup; __init_vec = &handle_exception_init; static void handle_exception_cleanup( void ) { static int orig_registers_set = 0; interruptible(0); // 禁止虚拟向量表中DEBUG串口中断 // Expand the HAL_SavedRegisters structure into the GDB register // array format. HAL_GET_GDB_REGISTERS(®isters[0], _hal_registers); // 拷贝_hal_registers中内容到GDB专用寄存器registers中 _registers = ®isters[0]; // 当前使用的register寄存器指向GDB专用寄存器 if (!orig_registers_set) { int i; for (i = 0; i < (sizeof(registers)/sizeof(registers[0])); i++) orig_registers[i] = registers[i]; _registers = &orig_registers[0]; // 将orig_registers作为下面操作语句临时使用的register寄存器 if (__is_breakpoint_function ()) // 如果当前PC位于breakpoint or trap instruction,那么if成立 __skipinst (); // pc+2或+4,调整pc数值,跳过当前位于breakpoint or trap instruction的语句 _registers = ®isters[0];// 将_registers还原回去 orig_registers_set = 1; } ... #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT // If we continued instead of stepping, when there was a break set // ie. we were stepping within a critical region, clear the break, and // that flag. If we stopped for some other reason, this has no effect. if ( cyg_hal_gdb_running_step ) { cyg_hal_gdb_running_step = 0; cyg_hal_gdb_remove_break(get_register (PC)); // 将break_buffer.targetAddr存放的pc处原始code内容,拷贝回*pc处,替换原有break内容. } // FIXME: (there may be a better way to do this) // If we hit a breakpoint set by the gdb interrupt stub, make it // seem like an interrupt rather than having hit a breakpoint. cyg_hal_gdb_break = cyg_hal_gdb_remove_break(get_register (PC)); #endif #if defined(HAL_STUB_HW_WATCHPOINT) || defined(HAL_STUB_HW_BREAKPOINT) // For HW watchpoint/breakpoint support, we need to know if we // stopped because of watchpoint or hw break. We do that here // before GDB has a chance to remove the watchpoints and save // the information for later use in building response packets. _hw_stop_reason = HAL_STUB_IS_STOPPED_BY_HARDWARE(_watch_data_addr); #endif } 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)) { // 如果当前pc就是break断点设置处,那么将暂存到break_buffer中的原始code代码恢复到break点[luther.gliethttp] 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); // 清空dcache __instruction_cache(CACHE_FLUSH); // 清空icache [luther.gliethttp] return 1; } return 0; } __handle_exception ==>__cleanup_vec ();即:handle_exception_cleanup(); ==> packages/hal/arm/arch/v2_0/src/arm_stub.c // Return the currently-saved value corresponding to register REG of // the exception context. target_register_t get_register (regnames_t reg) { target_register_t val; int offset = reg_offset(reg); if (REGSIZE(reg) > sizeof(target_register_t) || offset == -1) return -1; val = _registers[offset/sizeof(target_register_t)]; return val; } //==================== int __is_bsp_syscall(void) { unsigned long pc = get_register(PC); unsigned long cpsr = get_register(PS); // condition codes if (_hal_registers->vector == CYGNUM_HAL_EXCEPTION_INTERRUPT) { if (cpsr & CPSR_THUMB_ENABLE) return *(unsigned short *)pc == 0xdf18;//反汇编后为指令swi 24 else return *(unsigned *)pc == 0xef180001;//反汇编后为指令swi 0x00180001 } return 0; } luther@gliethttp:/vobs/ecos$ ghex2 luther.asm.bin 然后输入01 00 18 ef十六进制,保存. luther@gliethttp:/vobs/ecos$ arm-elf-objdump -DS -b binary -m arm luther.asm.bin 反汇编数据如下: luther.asm.bin: file format binary arm-elf-objdump: luther.asm.bin: no symbols Disassembly of section .data: 00000000 <.data>: 0: ef180001 swi 0x00180001 同样的反汇编thumb代码 luther@gliethttp:/vobs/ecos$ ghex2 luther.asm.bin 然后输入18 df十六进制,保存. luther@gliethttp:/vobs/ecos$ arm-elf-objdump -DS -b binary -m arm -M force-thumb luther.asm.bin luther.asm.bin: file format binary arm-elf-objdump: luther.asm.bin: no symbols Disassembly of section .data: 00000000 <.data>: 0: df18 swi 24 //==================== #define SYS_exit 1 #define SYS_interrupt 1000 int hal_syscall_handler(void) // 由packages/cygmon/v2_0/misc/arm/cpu.h|446|定义引用 // #define SYSCALL() asm volatile(" swi %0" : /* No outputs */ : "i" (SYSCALL_SWI)) { int func, arg1, arg2, arg3, arg4; int err, sig; #if 0 union arm_insn inst; // What is the instruction we were executing // inst.word = *(unsigned long *)(regs->_pc - ARM_INST_SIZE); // Not a syscall. Don't handle it if ((inst.swi.rsv1 != SWI_RSV1_VALUE) || (inst.swi.swi_number != SYSCALL_SWI)) return 0; #endif func = get_register(R0); arg1 = get_register(R1); arg2 = get_register(R2); arg3 = get_register(R3); arg4 = *(unsigned int *)(get_register(SP) + 4); if ((get_register(PS) & CPSR_MODE_BITS) == CPSR_SUPERVISOR_MODE) put_register(PC, get_register(IP)); else put_register(PC, get_register(LR)); if (func == SYS_interrupt) { // A console interrupt landed us here. // Invoke the debug agent so as to cause a SIGINT. return SIGINT; } if (__do_syscall(func, arg1, arg2, arg3, arg4, &err, &sig)) { put_register(R0, err); return sig; } return SIGTRAP; } 对系统调用的定义位于packages/redboot/v2_0/include/redboot.h #define SYS_exit 1 #define SYS_open 2 #define SYS_close 3 #define SYS_read 4 #define SYS_write 5 #define SYS_lseek 6 #define SYS_unlink 7 #define SYS_getpid 8 #define SYS_kill 9 #define SYS_fstat 10 CYG_ADDRWORD __do_syscall(CYG_ADDRWORD func, // syscall function number CYG_ADDRWORD arg1, CYG_ADDRWORD arg2, // up to four args. CYG_ADDRWORD arg3, CYG_ADDRWORD arg4, CYG_ADDRWORD *retval, CYG_ADDRWORD *sig) // syscall return value { int err = 0; *sig = 0; switch (func) { case SYS_open: { #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol __externC int cyg_hal_gdbfileio_open( const char *name, int flags, int mode, int *sig ); if (gdb_active) err = cyg_hal_gdbfileio_open((const char *)arg1, (int)arg2, (int)arg3, (int *)sig); else #endif err = sys_open((const char *)arg1, (int)arg2, (int)arg3); break; } ... } } |