基于A33下linux内核的GDB+KGDB内核调试环境搭建

基于A33的GDB+KGDB内核调试环境搭建

平台

  • 芯片:全志A33
  • 系统:Tina3.5
  • 内核:linux3.4
  • 通信方式:串口

修改内核配置文件

在内核配置文件.config中,打开如下选项:

配置项 开关 备注
CONFIG_KGDB y 加入KGDB支持
CONFIG_KGDB_SERIAL_CONSOLE y 使用KGDB通过串口与主机通信
CONFIG_DEBUG_INFO y 打开这个,使得内核包含基本信息
CONFIG_DEBUG_KERNEL y 打开这个,包含驱动调试信息

添加启动参数

在启动内核的时候,会读取内核启动参数。在启动参数一栏添加如下:

console=ttyS0,115200 kgdboc=ttyS0,115200

上述参数表明:终端使用串口ttyS0,通信波特率为115200;kgdb调试通信也使用串口ttyS0,通信波特率为115200。当内核启动时,会读取并解析这些参数,并触发相应的行为。

验证串口驱动是否支持kgdb调试

可以打开驱动程序,看下是uart_ops结构的对象下poll_get_char和poll_put_char函数指针是否有赋值。如果没有赋值,需要重新修改驱动,使其支持poll功能,添加poll功能后的驱动函数类似如下:
在这里插入图片描述

验证kgdb是否支持远程调试

使用gdb调试内核时出现:

Truncated register 19 in remote 'g' packet

这貌似一个gdb的bug,需要更改内核中kgdb的源码,更改如下:

------------------------- arch/arm/include/asm/kgdb.h -------------------------
index 48066ce..006793e 100644
@@ -75,7 +75,7 @@ extern int kgdb_fault_expected;
 
 #define KGDB_MAX_NO_CPUS	1
 #define BUFMAX			400
-#define NUMREGBYTES		(DBG_MAX_REG_NUM << 2)
+#define NUMREGBYTES		(GDB_MAX_REGS << 2)
 #define NUMCRITREGBYTES		(32 << 2)
 
 #define _R0			0

更改之后,再次验证一下,是可以成功启动gdb调试的。

使用agent-proxy复用串口

当只有一个串口用于调试时,我又想通过串口观察打印信息,又想通过串口调试内核,那么可以通过agent-proxy来复用串口。其中agent-proxy程序是运行在pc机器(开发机)上。

agent-proxy的下载地址是:agent-proxy下载

我下载的版本是1.96的,如图所示:
在这里插入图片描述

agent-proxy使用方法

其实比较简单,先下载下来,然后解压到自己的工作目录下,然后使用 make 编译形成二进制文件:

cd agent-proxy-1.96
make #make之后,会生成agent-ptoxy可执行文件,后面会使用到

使用例子(在人家的README中,也有类似介绍):

## 首先在你的终端中开启agent-proxy,其中5550表示终端打印显示的端口号;
## 5551表示gdb调试使用的远程端口号;ttyUSB0表示复用的串口。
./agent-proxy 5550^5551 0 /dev/ttyUSB0,115200 &
## 连接终端打印端口
telnet localhost 5550
## Boot the remote system with the kernel arg:  kgdboc=ttyS0,115200
## 当要调试的内核处于等待gdb连接状态时,这时可以通过gdb连接到目标端口
gdb ./vmlinux
target remote localhost:5551

按照上面操作后,可以一边断点调试内核,一边观察内核输出的打印信息:

在这里插入图片描述

当内核全速运行时:

在这里插入图片描述

pc端(开发机)的gdb调试步骤

首先进入到vmlinux(vmlinux是在编译内核过程中产生的未压缩的内核,它是elf可执行文件,用于内核debug,不可用于直接加载)文件目录下,进行如下操作:

当直接使用串口调试时:

arm-openwrt-linux-gdb ./vmlinux
set serial baud 115200
target remote /dev/ttyUSB0

当使用agent-proxy代理时:

arm-openwrt-linux-gdb ./vmlinux
target remote localhost:5551 # 5551是通过agent-proxy复用出来的端口

内核启动参数的选择

进入内核后,打开kgdb调试

如果想要调试加载的驱动时,可以进入到内核后再调试,这内核启动参数可以是:

console=ttyS0,115200 kgdbwait kgdboc=ttyS0,115200

然后编译内核,之后烧录到flash中,进行开机启动,可以进入到目标机内核文件系统中,在文件系统中进行如下操作可以打开kgdb:

echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc

在这里插入图片描述

当出现:

kgdb: Registered I/O driver kgdboc.
kgdb: Waiting for connection from remote gdb...

上述信息时,表明目标机(开发板)正在等待gdb连接。

这里面其实不用再次执行echo g > /proc/sysrq-trigger ,依然可以进入等待gdb的连接中。因为内核代码中的kgdboc中有检测到ttyS0配置参数时,会直接进入gdb连接中。涉及到的相关代码如下:

->param_set_kgdbts_var()
    ->configure_kgdbts()
    	->kgdb_register_io_module()
    		->kgdb_initial_breakpoint()
    			->kgdb_breakpoint()

进行驱动(.ko)调试

先把.ko文件放到目标机的文件系统目录下,然后进行加载:

insmod xxx.ko

加载成功后,会生成一些信息。之后查看加载模块的加载地址信息:

cat /proc/modules

在这里插入图片描述

上图的地址:0xbf106000就是gt9xxnew_ts模块加载的地址,这个地址在调试gt9xxnew_ts模块时会使用到。

这个时候,在开发机上进入远程gdb连接状态,使用上面获取的模块加载地址,进行调试加载的模块:

add-symbol-file  xxx.ko  text_address(ko)

上面指令执行后,gdb会读取模块的符号,这个时候就可以像调试应用层序一样调试驱动程序了:

在这里插入图片描述

进行到上面步骤后,就可以调试驱动文件了,但是美中不足的是,该方法无法调试模块的初始化函数,对于上面模块而言,断点是无法进入goodix_ts_init函数内部的,因为加载过程中已经执行过上面的初始化函数了,所以是无法再次进入初始化函数的。

如果想要调试模块的初始化函数怎么办,我目前采用的方法是将驱动模块直接编译进入内核影像中,在启动内核的时候进行调试,这样就可以调试指定模块的初始化函数了。

进入内核初,打开gdb调试

如果想要调试内核启动过程中的代码,就需要调整代码了:

------------------------- drivers/tty/serial/kgdboc.c -------------------------
index 2b42a01..7d5ac3d 100644
@@ -321,7 +321,7 @@ static int __init kgdboc_early_init(char *opt)
 early_param("ekgdboc", kgdboc_early_init);
 #endif /* CONFIG_KGDB_SERIAL_CONSOLE */
 
-module_init(init_kgdboc);
+core_initcall_sync(init_kgdboc);
 module_exit(cleanup_kgdboc);
 module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
 MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");

----------------------- drivers/tty/serial/sunxi-uart.c -----------------------
index 78dd9c2..48dc093 100644
@@ -2101,7 +2101,7 @@ static void __exit sunxi_uart_exit(void)
 	uart_unregister_driver(&sw_uart_driver);
 }
 
-module_init(sunxi_uart_init);
+core_initcall(sunxi_uart_init);
 module_exit(sunxi_uart_exit);
 
 MODULE_AUTHOR("Aaron<leafy.myeh@allwinnertech.com>");

上述更改是为了提高终端串口模块和kgdboc模块的初始化优先级。这种情况下,可在内核初期进入到kgdb连接等待中,用于调试内核初始化程序。

将上述代码重新编译烧录到emmc中,上电启动:

在这里插入图片描述

可以看到在启动内核初,kgdb已经在等待远程连接了,这个时候就可以像上面那种方法继续调试了。

这个个更改有一个缺点,就是串口终端无法登录了,不过不影响kgdb调试。

总结

  • 此种是以串口方法进行搭建kgdb调试环境的,如果通过网络的话,需要使用到其他的模块
发布了62 篇原创文章 · 获赞 9 · 访问量 6625
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览