各位大侠:
我已经使用U-boot作为bootloader在ATMEL AT91RM9200能够引导起Linux了,现在 想往这个U-boot里加入一段GDB-Stub程序,使得PC主机能够通过GDB和9200开发板(目标机)的stub调试桩交互来实现设置软件断点、单步执行等功能,简要说明一下其原理:(转载某网友的文章)
设计原理 
1.1远程调试原理图: 
当使用GDB(HOST)调试目标扳(TARGET)上的程序时,HOST需要通过UART或ETHERNET口与TARGET进行通讯,并传输命令;TARGET根据接收的包,解析命令,执行相应的动作,然后上传相应的包。 
1.2基于STUB的调试方法原理图:
 
1.3 STUB的工作原理: 
1、 Stub程序驻留在内核中,在系统完全启动之前先启动stub。 
2、 Stub通过指定的Debug通讯协议(如GDB远程调试协议)与主机的Debug程序交互。 
3、 Stub接管目标机的udef exception handler。 
4、 Stub接管对目标机通讯口 (串口、并口或网口)的控制。 
5、 实时调试要求目标机支持单步、断点等调试机制。 
2、实现方法 
2.1 几个主要函数: 
在linux的源代码中的stub的主程序名一般为gdb-stub.c。它的主要函数为handle_exception(),它是断点异常的处理函数;breakpoint()的主要任务是启动stub;set_debug_traps()用于初始化stub。 
2.2 stub的启动过程: 
通常将set_debug_traps()放在irq.c中init_irq()函数的末尾,其后紧跟着breakpoint()。set_debug_traps()函数一直扫描串口(如果通过串口调试的话),直到接收到HOST发出的同步信号(即两个字符:’$’和’#’),然后退出。breakpoint()中是一些汇编指令,其中包括一个断点指令,当CPU执行了这个断点指令时,就会产生一个断点异常,从而将控制权交给stub。 
Stub接到控制权后,会运行handle_exception(),从而与HOST进行通讯。具体的操作可以看源代码,很容易看懂。 
2.3 断点指令 
不同的CPU有不同的断点指令,它是一个汇编指令:mips的是break,它会产生一个断点异常。而对于ARM,在ARMv5及其以上版中有一个断点指令BKPT,而在低版本的指令集中,就没有该指令。解决方法是需要使用一个非定义指令代替断点指令,非定义指令就是ARM指令集中没有的指令,它会产生一个非定义指令(udef)异常,从而达到断点异常的效果。
对于ARM的breakpoint(),它的代码如下: 
void breakpoint(void) 
{ 
int i, j; 
if (!initialized) 
return; 
__asm__ __volatile__(" 
.globl breakinst 
nop 
breakinst: nop 
nop 
nop 
"); 
} 
当然,这个代码不能产生异常,这就需要在set_debug_traps()添加一行代码: 
void set_debug_traps(void)      
{ 
……                                     //不知道在这里做了些什么?
*(unsigned long *)breakinst = BP; 
…… 
} 
其中,BP就是一个非定义指令: 
#define BP 0xe7fddefe     
这样在初始化时,执行完set_debug_traps(void)后,进入void breakpoint(void)就会产生一个udef异常,从而将控制权交给stub。 
2.4 异常处理函数 
其实handle_exception()是由底层由汇编指令写成的异常处理函数调用的。对于mips,它的底层处理函数是由gdb-low.S实现的。它的主函数是trap_low,它的功能是:当发生断点异常时,将所有寄存器存入堆栈中,并以此作为参数调用handle_exception(),当从函数handle_exception()返回时,再恢复原来的寄存器。 
对于ARM来说,它没有断点异常,这就需要在它的udef异常处理函数do_undefinstr()中加入一些检查和调用handle_exception()的语句。
请教ARM的udef异常的底层处理函数该怎么写!? 
2.5 设置断点和单步 
调试程序时,最重要的莫过于设置断点和单步执行。而单步的最终的工作也就是设置断点。在stub中,设置断点时,要先将指定地址处的数据保存在一个变量中,然后再将该处替换成断点指令。当从异常处理函数返回时,内核继续运行,当运行到断点指令时,又会进入handle_exception(),handle_exception()首先会将原来的指令恢复到断点处,然后等待HOST的命令。具体的操作可以看源代码。 
3、操作方法 
1) 下载GDB的源代码,如gdb-5.0 
2) 执行如下指令: 
cd gdb-5.0 
./configure --target=arm-linux 
make(生成gdb) 
make install(生成arm-linux-gdb,并存入/usr/local/bin/) 
3) 将内核Image下载到目标板上,并运行。 
4) 运行如下指令: 
/usr/local/bin/arm-linux-gdb –b 9600 vmlinux 
set remotedevice /dev/ttyS1 
set debug remote 1(可选) 
target remote /dev/ttyS1(当stub通过UART1打出提示信息后再运行该命令) 
5) 运行GDB命令进行调试。 
4、串行协议 
在gdb的info页中有串行协议的详细解释。 
由于时间仓促,不足之处还请各位指教!
但是遇到一个如何设置异常向量表的问题,就是想利用异常向量表中的未定义指令异常Undefined instruction 来产生未定义指令异常中断,从而转去执行handle_exception()程序。如何实现异常向量表的重定位(Flash —〉SDRAM)?U-boot中Start.S源代码:
#include "config.h"
#include "version.h"
/*
 *************************************************************************
 *
 * Jump vector table as in table 3.1 in [1]
 *
 *************************************************************************
 */
.globl _start
_start: b reset
 ldr pc, _undefined_instruction         //如何利用这条指令
 ldr pc, _software_interrupt
 ldr pc, _prefetch_abort
 ldr pc, _data_abort
 ldr pc, _not_used
 ldr pc, _irq
 ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort:  .word data_abort
_not_used:  .word not_used
_irq:   .word irq
_fiq:   .word fiq
.balignl 16,0xdeadbeef
/*
 *************************************************************************
 *
 * Startup Code (reset vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************
 */
/*
 * CFG_MEM_END is in the board dependent config-file (configs/config_BOARD.h)
 */
_TEXT_BASE:
 .word TEXT_BASE
.globl _armboot_start
_armboot_start:
 .word _start
/*
 * Note: _armboot_end_data and _armboot_end are defined
 * by the (board-dependent) linker script.
 * _armboot_end_data is the first usable FLASH address after armboot
 */
.globl _armboot_end_data
_armboot_end_data:
 .word armboot_end_data
/*
 * Note: armboot_end is defined by the (board-dependent) linker script
 */
.globl _armboot_end
_armboot_end:
 .word armboot_end
/*
 * _armboot_real_end is the first usable RAM address behind armboot
 * and the various stacks
 */
.globl _armboot_real_end
_armboot_real_end:
 .word 0x0badc0de
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
 .word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
 .word 0x0badc0de
#endif
/*
 * the actual reset code
 */
reset:
 /*
  * set the cpu to SVC32 mode  */
 mrs     r0,cpsr 
bic     r0,r0,#0x1f         
orr     r0,r0,#0x13 
msr cpsr,r0
/*
  * relocate exeception table  */以下这一段时干什么用的?它怎么就能实现relocate exeception table  功能呢?
 ldr r0, =_start          
 ldr r1, =0x0            
 mov r2, #16              //R2=16
copyex:
 subs r2, r2, #1           
 ldr r3, [r0], #4         
 str r3, [r1], #4        
 bne copyex
 /*
  * we do sys-critical inits only at reboot,
  * not when booting from ram!
  */
#ifdef CONFIG_INIT_CRITICAL
 bl      cpu_init_crit
#endif
 /* set up the stack */
 ldr     r0, _armboot_end           
 add     r0, r0, #CONFIG_STACKSIZE
 sub     sp, r0, #12             /* leave 3 words for abort-stack */
 ldr pc,_start_armboot
_start_armboot: .word start_armboot
/*
 *************************************************************************
 *
 * CPU_init_critical registers
 *
 *************************************************************************
 */
cpu_init_crit:
 # actually do nothing for now!
 mov pc, lr   
/*
 *************************************************************************
 *
 * Interrupt handling
 *
 *************************************************************************
 */
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR  64
#define S_PC  60
#define S_LR  56
#define S_SP  52
#define S_IP  48
#define S_FP  44
#define S_R10  40
#define S_R9  36
#define S_R8  32
#define S_R7  28
#define S_R6  24
#define S_R5  20
#define S_R4  16
#define S_R3  12
#define S_R2  8
#define S_R1  4
#define S_R0  0
#define MODE_SVC 0x13
#define I_BIT  0x80
/*
 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
 */
 .macro bad_save_user_regs
 sub sp, sp, #S_FRAME_SIZE
 stmia sp, {r0 - r12}   @ Calling r0-r12
 add     r8, sp, #S_PC
 ldr r2, _armboot_end
 add r2, r2, #CONFIG_STACKSIZE
 sub r2, r2, #8
 ldmia r2, {r2 - r4}                   @ get pc, cpsr, old_r0
 add r0, sp, #S_FRAME_SIZE  @ restore sp_SVC
 add r5, sp, #S_SP
 mov r1, lr
 stmia r5, {r0 - r4}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_r
 mov r0, sp
 .endm
 .macro irq_save_user_regs
 sub sp, sp, #S_FRAME_SIZE
 stmia sp, {r0 - r12}   @ Calling r0-r12
 add     r8, sp, #S_PC
 stmdb   r8, {sp, lr}^                   @ Calling SP, LR
 str     lr, [r8, #0]                    @ Save calling PC
 mrs     r6, spsr
 str     r6, [r8, #4]                    @ Save CPSR
 str     r0, [r8, #8]                    @ Save OLD_R0
 mov r0, sp
 .endm
 .macro irq_restore_user_regs
 ldmia sp, {r0 - lr}^   @ Calling r0 - lr
 mov r0, r0
 ldr lr, [sp, #S_PC]   @ Get PC
 add sp, sp, #S_FRAME_SIZE
 subs pc, lr, #4   @ return & move spsr_svc into cpsr
 .endm
 .macro get_bad_stack
 ldr r13, _armboot_end  @ setup our mode stack
 add r13, r13, #CONFIG_STACKSIZE @ resides at top of normal stack
 sub r13, r13, #8
 str lr, [r13]   @ save caller lr / spsr
 mrs lr, spsr
 str     lr, [r13, #4]
 mov r13, #MODE_SVC   @ prepare SVC-Mode
 msr spsr_c, r13
 mov lr, pc
 movs pc, lr
 .endm
 .macro get_irq_stack   @ setup IRQ stack
 ldr sp, IRQ_STACK_START
 .endm
 .macro get_fiq_stack   @ setup FIQ stack
 ldr sp, FIQ_STACK_START
 .endm
/*
 * exception handlers
 */
 .align  5
undefined_instruction:       //想让这里转去执行自己的程序该做些什么呢?
 get_bad_stack
 bad_save_user_regs
 bl  do_undefined_instruction
 .align 5
software_interrupt:
 get_bad_stack
 bad_save_user_regs
 bl  do_software_interrupt
 .align 5
prefetch_abort:
 get_bad_stack
 bad_save_user_regs
 bl  do_prefetch_abort
 .align 5
data_abort:
 get_bad_stack
 bad_save_user_regs
 bl  do_data_abort
 .align 5
not_used:
 get_bad_stack
 bad_save_user_regs
 bl  do_not_used
#ifdef CONFIG_USE_IRQ
 .align 5
irq:
 get_irq_stack
 irq_save_user_regs
 bl  do_irq
 irq_restore_user_regs
 .align 5
fiq:
 get_fiq_stack
 /* someone ought to write a more effiction fiq_save_user_regs */
 irq_save_user_regs
 bl  do_fiq
 irq_restore_user_regs
#else
 .align 5
irq:
 get_bad_stack
 bad_save_user_regs
 bl  do_irq
 .align 5
fiq:
 get_bad_stack
 bad_save_user_regs
 bl  do_fiq
#endif
 .align 5
.globl reset_cpu
reset_cpu:
 mov     pc, r0
请AT91高手多多指教,谢谢!

 
					
				
 
			
			
			
						
			 请高手讲解原因。
请高手讲解原因。 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

