qemu结合gdb调试龙芯1c的裸机程序helloworld

测试环境

Windows 8上运行qemu(qemu中自带gdbserver)
IP: 192.168.3.102
Qemu: qemu-w64-setup-20170824.exe

虚拟机中运行为龙芯1c编译的gdb(不能使用系统自带的gdb,除非是使用的龙芯的pc)
IP: 192.168.3.200
Gdb: gdb-7.0.1a.tar.bz2

Helloworld的linux工具链使用龙芯官方推出的gcc-4.3-ls232.tar.gz
RT-Thread的Linux下的交叉编译工具链mips-2015.05-19-mips-sde-elf-i686-pc-linux-gnu.tar.bz2

以上所用到的软件可以到官网下载,也可以去我网盘http://pan.baidu.com/s/1miuYGze

安装qemu

qemu重自带gdb server。

我是在windows 8上使用的qemu,按照和其它软件一样,双击安装就可以了,安装完成后可能需要手动将目录“C:\Program Files\qemu”添加到环境变量。这里需要用到的可执行文件“qemu-system-mipsel.exe”就在该目录中。

编译龙芯1c的gdb

GDB远程调试套件包括Host端的gdb和Target端的gdbserver,对于gdb,宿主机上发行版本自带的(x64)PC版gdb是不能用的,它没有目标架构(MIPS)相关的调试支持。所以我们应该使用gdb的源码,针对MIPS平台编译一个(toolchain还是Host上的)特别的版本
 ./configure --target=mipsel-linux --prefix=/home/gdb/gdb-dest --program-prefix=mipsel-linux-

测试全过程

启动qemu(自带gdbserver)

在windows上的命令窗口中运行如下命令启动qemu
qemu-system-mipsel -M mips -nographic -kernel bin/image.elf -gdb tcp::1234 -S
其中,-M mips指定machine为mips r4k platform。可以通过命令“qemu-system-mipsel -M ?”查看支持那些machine,用命令“qemu-system-mipsel -cpu ?”查看支持那些cpu。

-kernel后的bin/image.elf为本次调试对象,即运行在qemu上的可执行程序;
-gdb tcp:1234的作用是打开qemu中的gdbserver,并且使用tcp,端口为1234;
最后的一个参数“-S”的作用是qemu启动后立刻挂起gdbserver,等待客户端gdb的连接。

运行mipsel-linux-gdb并开始调试

运行mipsel-linux-gdb并连接qemu中的gdbserver

运行前面已经编译好的mipsel-linux-gdb,并用命令”target remote 192.168.3.102:1234”连接qemu中的gdbserver。

命令”target remote 192.168.3.102:1234“中的IP地址192.168.3.102为运行qemu的PC,端口1234为启动qemu时,传给qemu的gdbserver监听的端口。

读取符号表

编译源码时,在Makefile中加入了编译选项”-g“,所以符号表已经在可执行文件”bin/image.elf“中,那么使用命令”symbol-file”读取即可,如下

扫描二维码关注公众号,回复: 1565171 查看本文章

好,现在可以开始单步,打断点调试了

单步调试

单步执行最开始那段汇编,源码如下

    .text
    .globl _start
_start:
	b		reset
	nop

	.org 0x180
	/* General exception */
1:	b	1b
	nop

	.align 4

reset:
	/* Clear CP0_SR:BEV to 0 */
	mfc0	$t0, $12
	and		$t0, 0xffbfffff
	mtc0	$t0, $12

	/* Setup stack address */
    lui     $sp, %hi(stack_top)
    addiu   $sp, $sp, %lo(stack_top)
    lui     $t9, %hi(main)
    addiu   $t9, %lo(main)
    jalr    $t9
    nop
hang:
	b       hang

调试过程如下

第一个单步,执行了一条汇编指令”mfc0    $t0, $12”,并提示自动切换到汇编模式
然后执行list命令,显示了当前上下文代码,可以看到其后的第二条汇编指令为”and        $t0, 0xffbfffff”
第二个单步,执行了汇编指令”and        $t0, 0xffbfffff”
第三个单步,执行了汇编指令”mtc0    $t0, $12”

打断点

在main函数处打个断点

注意右边为qemu中还没有打印helloworld,代码中13行打印helloworld,那么在15行再打个断点看看

测试源码

这里只贴部分源码,完整的代码请移步到https://gitee.com/caogos/qemu_gdb_mips_hello

start.S

    .text
    .globl _start
_start:
	b		reset
	nop

	.org 0x180
	/* General exception */
1:	b	1b
	nop

	.align 4

reset:
	/* Clear CP0_SR:BEV to 0 */
	mfc0	$t0, $12
	and		$t0, 0xffbfffff
	mtc0	$t0, $12

	/* Setup stack address */
    lui     $sp, %hi(stack_top)
    addiu   $sp, $sp, %lo(stack_top)
    lui     $t9, %hi(main)
    addiu   $t9, %lo(main)
    jalr    $t9
    nop
hang:
	b       hang

main.c

#include <bsp.h>
#include <uart.h>

int main()
{
	unsigned int tt = 0;
	int i = 0;

	// Test exception
	//writel(0xffffffff, 0x12341234);

	init_serial();
	print_uart0("Hello world!\n");

	for (i = 0 ; i < 10 ; i++) {
		tt = read_c0_count();
	}
	// Never return
	while(1);

	return 0;
}


uart.h

#ifndef __UART_H__
#define __UART_H__

//Define
#define UART0_BASE 0xB40003F8	/* 16550 COM1 */

// API
void init_serial(void);
void print_uart0(const char *s);
void putc(char a);

#endif

uart.c

#include <bsp.h>
#include <uart.h>

static int is_transmit_empty()
{
 	volatile char *addr = (volatile char *)(UART0_BASE + 5);

	return *addr & 0x20;
}

void putc(char a)
{
	volatile char *addr = (volatile char*)UART0_BASE;

	while (is_transmit_empty() == 0);
	*addr = a;
}

void print_uart0(const char *s)
{
	while (*s != '\0') { /* Loop until end of string */
		putc(*s);
		s++; /* Next char */
	}
}

void init_serial()
{
	writeb(0xc1, UART0_BASE + 2);
	writeb(0x03, UART0_BASE + 3);
	writeb(0x03, UART0_BASE + 4);
	writeb(0x60, UART0_BASE + 5);
	writeb(0xb0, UART0_BASE + 6);
	writeb(0x00, UART0_BASE + 7);
}

Makefile

OBJDIR = obj/
BINDIR = bin/
DRVDIR = Drivers/

CROSS_COMPILE = mipsel-linux-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
AS = $(CROSS_COMPILE)as
AR = $(CROSS_COMPILE)ar
OBJCOPY = $(CROSS_COMPILE)objcopy

SYS_INC = include/
DRV_INC =Drivers/include/
INC_FLAGS += -I$(SYS_INC) -I$(DRV_INC)

CFLAGS += -mips32 -EL -Wall -g -fno-exceptions -fno-builtin -mno-abicalls -nostdinc -fno-stack-protector
LDFLAGS += -nostdlib -nostartfiles -nodefaultlibs -EL

ELF_IMAGE = $(BINDIR)image.elf
TARGET = $(BINDIR)image.bin

LINKER_SCRIPT = boot.ld

APP_OBJS += main.o
STARTUP_OBJ += start.o
DRIVER_OBJ += uart.o

OBJS = $(addprefix $(OBJDIR), $(STARTUP_OBJ) $(DRIVER_OBJ) $(APP_OBJS))

all: $(TARGET)

$(TARGET):$(OBJDIR) $(BINDIR) $(ELF_IMAGE)
	$(OBJCOPY) -O binary $(ELF_IMAGE) $(TARGET)

$(ELF_IMAGE):$(OBJS)
	$(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) $(OBJS) -o $@


$(OBJDIR)start.o:start.S
	$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR)main.o:main.c
	$(CC) $(CFLAGS) $(INC_FLAGS) -c $< -o $@

# Drivers
$(OBJDIR)uart.o:$(DRVDIR)uart.c
	$(CC) $(CFLAGS) $(INC_FLAGS) -c $< -o $@


$(OBJDIR):
	mkdir -p $@
$(BINDIR):
	mkdir -p $@
clean:
	rm -rf obj bin

boot.ld

ENTRY(_start)
SECTIONS
{
	. = 0x80000000;
	.startup . : { obj/start.o(.text) }
	.text : { *(.text) }
	.data : { *(.data) }
	.bss : { *(.bss) }
	. = . + 0x1000; /* 4kB of stack memory */
	stack_top = .;
}



虽然源码中的串口基地址目前还不是龙芯1c的,但演示一个非常精简的,使用串口打印调试信息的例子,还是很有参考意义的。

查看qemu帮助信息

查看支持的CPU型号

使用命令“qemu-system-mipsel -cpu ?”查看支持的cpu型号,简单来说就是在命令后面跟一个问号,就会把支持的所以cpu型号打印出来。如下

D:\VmShare\rt-thread\bsp\ls1cdev>qemu-system-mipsel -cpu ?
MIPS '4Kc'
MIPS '4Km'
MIPS '4KEcR1'
MIPS '4KEmR1'
MIPS '4KEc'
MIPS '4KEm'
MIPS '24Kc'
MIPS '24KEc'
MIPS '24Kf'
MIPS '34Kf'
MIPS '74Kf'
MIPS 'M14K'
MIPS 'M14Kc'
MIPS 'P5600'
MIPS 'mips32r6-generic'


查看支持的Machine

使用命令“qemu-system-mipsel -M ?”或“qemu-system-mipsel -machine ?”查看支持的Machine

D:\VmShare\qemu_gdb_rtt_ls1c\bsp\ls1cdev>qemu-system-mipsel -machine ?
Supported machines are:
ar7-amd              MIPS AR7 with AMD flash
ar7                  MIPS 4KEc / AR7 platform
fbox-4mb             FBox 4 MiB flash (AR7 platform)
fbox-8mb             FBox 8 MiB flash (AR7 platform)
malta                MIPS Malta Core LV (default)
mips                 mips r4k platform
mipsel               misp r4k platform (little endian)
mipssim              MIPS MIPSsim platform
none                 empty machine
sinus-basic-3        Sinus DSL Basic 3 (AR7 platform)
sinus-basic-se       Sinus DSL Basic SE (AR7 platform)
sinus-se             Sinus DSL SE (AR7 platform)
speedport            Speedport (AR7 platform)
tnetd7200            MIPS 4KEc / TNETD7200 platform
tnetd7300            MIPS 4KEc / TNETD7300 platform

D:\VmShare\qemu_gdb_rtt_ls1c\bsp\ls1cdev>qemu-system-mipsel -M ?
Supported machines are:
ar7-amd              MIPS AR7 with AMD flash
ar7                  MIPS 4KEc / AR7 platform
fbox-4mb             FBox 4 MiB flash (AR7 platform)
fbox-8mb             FBox 8 MiB flash (AR7 platform)
malta                MIPS Malta Core LV (default)
mips                 mips r4k platform
mipsel               misp r4k platform (little endian)
mipssim              MIPS MIPSsim platform
none                 empty machine
sinus-basic-3        Sinus DSL Basic 3 (AR7 platform)
sinus-basic-se       Sinus DSL Basic SE (AR7 platform)
sinus-se             Sinus DSL SE (AR7 platform)
speedport            Speedport (AR7 platform)
tnetd7200            MIPS 4KEc / TNETD7200 platform
tnetd7300            MIPS 4KEc / TNETD7300 platform


龙芯官方的qemu

龙芯官方有最新的,支持龙芯1c的qemu,使用上和qemu官网下载的有点区别,网盘(本文前面有链接)中有个简要的说明文档,串口信息通过vncviewer查看,但目前我始终未能看到串口打印,有会的欢迎留言分享,谢谢!

http://ftp.loongnix.org/embed/ls1c/qemu-ls1c.tar.gz

http://ftp.loongnix.org/embed/ls1b/simulator/qemu.pdf

这是龙芯qemu配套说明文档中的部分截图。另外把测试时使用的命令也贴上,仅供参考

export PATH=$PATH:/home/develop/test/qemu-ls1c/qemu386/bin
qemu-system-mipsel -M ls1c -serial vc -kernel bin/image.elf -gdb tcp::1234 -S
target remote localhost:1234
symbol-file /mnt/hgfs/VmShare/qemu_gdb_mips_hello/bin/image.elf
vncview 127.0.0.1:5900



猜你喜欢

转载自blog.csdn.net/caogos/article/details/78051111