Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15501777
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类:

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' as '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;
      }
      ...
    }
}
阅读(4690) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~