一、命令行调试(gdb)
程序参考自
http://balau82.wordpress.com/2010/08/17/debugging-arm-programs-inside-qemu/
启动的汇编片段(startup.s)
.global _Reset _Reset: LDR sp, =stack_top BL c_entry B .
链接脚本(test.ld)
ENTRY(_Reset) SECTIONS { . = 0x10000; .startup . : { startup.o(.text) } .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } . = . + 0x1000; /* 4kB of stack memory(4kB的堆栈内存)*/ stack_top = .; }
(修改二进制文件布局的另一种做法是使用ld的命令行,或既使用-T开关又使用命令行)
主程序(test.c):
volatile unsigned int * const UART0DR = (unsigned int *)0x101f1000; void print_uart0(const char *s) { while(*s != '\0') { /* Loop until end of string (循环直至字符串结束)*/ *UART0DR = (unsigned int)(*s); /* Transmit char (发送字符)*/ s++; /* Next char (下一个字符)*/ } } void c_entry() { print_uart0("Hello world!\n"); }
(UART是串口的底层实现,严格来说它是一块芯片,但在嵌入式开发中经常指操纵串口的I/O端口和特殊寄存器,使用方式和内存访问很相似,所以经常用于输出调试信息)
qemu调试批处理文件(qemu_test.bat):
"D:\java\qemu-0.9.0-arm\qemu-system-arm.exe" -s -S -M versatilepb -m 128M -kernel test.bin pause
(我使用的是模拟ARM的qemu,注意qemu-system-arm和-M开关,versatile pb是一种使用ARM926EJ-S的开发板)
gdb调试脚本(gdbinit.txt):
file test.elf target remote localhost:1234 b c_entry cont
(可以手工输入到gdb控制台,b是breakpoint的缩写)
(file命令用于加载调试信息,所以elf文件在编译时需要加入-g开关)
(target用于远程调试,前提是远程机器运行gdbserver监听1234端口,这里qemu模拟器已经有gdbserver的功能)
(设置程序参数可以用set args,运行程序可以用run)
构建文件(Makefile):
# see http://balau82.wordpress.com/2010/08/17/debugging-arm-programs-inside-qemu/ # for debug: # make clean all # for release: # make clean all DEBUG="" PROJECT := test OBJS := startup.o test.o DEBUG := -g ARGS := -mcpu=arm926ej-s ${DEBUG} EMU := qemu_test.bat AS := arm-none-eabi-as ${ARGS} CC := arm-none-eabi-gcc ${ARGS} LD := arm-none-eabi-ld -T ${PROJECT}.ld -Map ${PROJECT}.map GDB := arm-none-eabi-gdb --command=gdbinit.txt RUN := arm-none-eabi-run SIZE := arm-none-eabi-size OBJCOPY := arm-none-eabi-objcopy -O binary RM := rm -f all:${PROJECT}.bin ${PROJECT}.bin:${PROJECT}.elf ${SIZE} $< ${OBJCOPY} $< $@ ${PROJECT}.elf:${OBJS} ${LDSCRIPT} ${LD} ${OBJS} -o $@ %.o:%.s ${AS} $< -o $@ %.o:%.c ${CC} -c ${ARGS} $< -o $@ #run:all # ${GDB} ${PROJECT}.elf run:all start ${EMU} ${GDB} clean: ${RM} *.o *.elf *.bin *.map
(我写的Makefile实在不敢恭维...,惯常方法是使用CFLAGS变量)
(变量值可以用make的参数覆盖,例如make clean all DEBUG="")
(tab缩进是必须的