gdb 多线程调试 暂停其他线程_用 kGDB 调试 Linux 内核

欢迎点击上方蓝色“泰晓科技”关注我们7df1a1f8e6b0af0c7141ae622451fb82.png

作者:文平波

225256fd55f8763fae8e5bbbaaa98730.png

图片来源自网络

1 简介

这个文档记录了用 kGDB 调试 Linux 内核的全过程,都是在前人工作基础上的一些总结。以下操作都是基于特定板子来进行,但是大部分都能应用于其他平台。

要使用 KGDB 来调试内核,首先需要修改 config 配置文件,打开相应的配置,配置内核启动参数,甚至修改串口驱动添加 poll 支持,然后才能通过串口远程调试内核。

2 配置内核

2.1 基本配置

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

d240fc7e0d40cb1b1b7e070cb3c45060.png

2.2 可选选项

b8f62e4a01ca793b643063b66ea01723.png

2.3 启动参数

打开相应的选项后,需要配置 kernel 启动参数,使 KGDB 和内核能够找到正确的通信接口。如果是使用串口,则需要配置如下选项:

console=ttySAC3,115200 kgdboc=ttySAC3,115200

如果需要调试内核的启动过程,则需要在 kgdboc 后面加入 kgdbwait 。

在其他板子上,若使用以太网口来和 KGDB 进行通信,则要把 kgdboc 换成 kgdboe(kgdb over ethernet) )。

配置完后,就可以正常编译,然后把内核下载到目标板上面。

3 串口驱动修改

如果在内核启动的过程中出现如下错误提示:

kgdb: Unregistered I/O driver, debugger disabled.

则需要根据这一部分,修改串口驱动程序,若能正常进入 kgdb ,则忽略该节,直接进入下一节使用 KGDB 。

drivers/tty/serial/kgdboc.c 中的 configure_kgdboc 函数,会通过 tty_find_polling_driver(cptr, &tty_line) 来找寻内核启动参数中指定的串口驱动。然后通过 kgdboc_get_char()kgdboc_put_char() 来和主机串口正常通信。

可以看到在 config 配置文件的 CONFIG_CONSOLE_POLL 就是使能串口与 kgdboc 的接口。如果 tty_find_polling_driver 没有找到对应的串口通信接口,则会调用 kernel/debug/debug_core.c 中的 kgdb_unregister_io_module 进行错误处理。

有的板子的串口驱动并没有加入对 kgdboc 通信的支持,例如 Samsung 的串口驱动需要在 drivers/tty/serial/samsung.c 中手动添加。  添加与 kgdboc 通信的接口,只需添加一个发送函数和接收函数,然后在驱动操作结构体中加入对应的函数就可以了。具体的 PATCH 如下:

drivers/tty/serial/samsung.c | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index ff6a4f8..5ceb7d7 100755
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -893,7 +893,29 @@ static struct console s3c24xx_serial_console;
#define S3C24XX_SERIAL_CONSOLE NULL
#endif

+#ifdef CONFIG_CONSOLE_POLL
+static void s3c24xx_serial_poll_put_char(struct uart_port *port, unsigned char c)
+{
+    while (!(rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE))
+       ;
+
+    wr_regl(port, S3C2410_UTXH, c);
+}
+
+static int s3c24xx_serial_poll_get_char(struct uart_port *port)
+{
+    while (!(rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_RXDR))
+        ;
+
+    return rd_regl(port, S3C2410_URXH);
+}
+#endif
+
static struct uart_ops s3c24xx_serial_ops = {
+#ifdef CONFIG_CONSOLE_POLL
+    .poll_get_char = s3c24xx_serial_poll_get_char,
+    .poll_put_char = s3c24xx_serial_poll_put_char,
+#endif
     .pm = s3c24xx_serial_pm,
     .tx_empty = s3c24xx_serial_tx_empty,
     .get_mctrl = s3c24xx_serial_get_mctrl,
--
1.7.5.4

加入这个 patch ,重新编译内核,之后就能正常进入 kgdb

4 gdb 远程调试

如果在内核启动参数中加入了 kgdbwait ,则内核会在完成基本的初始化之后,停留在 kgdb 的调试陷阱中,等待主机的 gdb 的远程连接。

由于大部分的板子只有一个调试串口,所以你需要把之前与串口通信的 minicom 退出来,然后在内核源码的目录下,执行以下命令:

$ arm-linux-gnueabi-gcc vmlinux
(gdb) target remote /dev/ttyUSB0
(gdb) set detach-on-fork on
(gdb) b panic()
(gdb) c

当然,你也可以 agent-proxy 来复用一个串口,通过虚拟出两个 TCP 端口。这时候, gdb 就需要用 target remote 命令连接 kgdb ,例如:

(gdb) target remote localhost:5551

agent-proxy 可这样下载:

git clone git://git.kernel.org/pub/scm/utils/kernel/kgdb/agent-proxy.git

具体用法,请看该 repo 下的 README 。

在用 gdb 来调试内核的时候,由于内核在初始化的时候,会创建很多子线程。而默认 gdb 会接管所有的线程,如果你从一个线程切换到另外一个线程, gdb 会马上把原先的线程暂停。但是这样很容易导致 kernel 死掉,所以需要设置一下 gdb 。一般用 gdb 进行多线程调试,需要注意两个参数:follow-fork-modedetach-on-fork

  • detach-on-fork 参数,指示 GDB 在 fork 之后是否断开(detach)某个进程的调试,或者都交由 GDB 控制:set detach-on-fork [on|off]

    • on: 断开调试 follow-fork-mode 指定的进程。

    • off: gdb将控制父进程和子进程。

  • follow-fork-mode 指定的进程将被调试,另一个进程置于暂停(suspended)状态。follow-fork-mode 的用法为:set follow-fork-mode [parent|child]

    • parent: fork之后继续调试父进程,子进程不受影响。

    • child: fork之后调试子进程,父进程不受影响。

5 参考资料

  • gdb user mannual: http://sourceware.org/gdb/current/onlinedocs/gdb/

  • gdb internal: http://www.sourceware.org/gdb/onlinedocs/gdbint.html

  • kgdb/kdb official website: https://kgdb.wiki.kernel.org/

  • kernel debug usage: http://www.kernel.org/doc/htmldocs/kgdb.html

  • kdb in elinux.org: http://elinux.org/KDB

  • multi-threads debug in gdb: http://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/

  • KGDB.info: http://www.kgdb.info/

注:由于微信公众号无法在正文中嵌入外部链接,所以这里的文章为增强阅读体验移去了部分外部链接。如果您希望获取正文中的外部链接请移步本文文末左下方点击 “”。


33faa4d2a2a4be12de03fd13d3a87a19.png

上课啦!上课啦!

近日,泰晓科技与阅码场强强联合,首度推出程序员自我修养之 「360° 剖析 Linux ELF」在线视频课程。如果您想进一步提升自己的实力,掌握更多有关 Linux 环境下程序编译、链接、运行的底层奥秘,欢迎点击  "课程介绍"  进入相关页面了解更多讯息。

fee54918137af1aa3354f7b5f5ab7ac6.png


8d95363e374f4006aad9c577d1028eff.png

8b5a8391ad2ea72d9a38f7ea948fff65.png关注“泰晓科技”!点“在看”

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值