kgdb调试aarch64内核模块

0 开发环境

  • 笔记本:ubuntu18.04.5,内核版本为5.3
  • 开发板:imx8mp-evk
  • 内核版本:Linux5.4.24
  • 交叉编译工具链:fsl-imx-xwayland-glibc-x86_64-imx-image-core-aarch64-imx8mpevk-toolchain-5.4-zeus.sh

注:下面的可能会遗漏部分细节,但主要的部分基本都写出来了,应该无大碍。
注:以下步骤虽然针对的imx8mp-evk,但只要是aarch64架构的芯片,大部分操作都通用的。
注:这是个人的踩坑记录,虽然可以解决问题,但估计不是最好的解决方案,欢迎评论区一起探讨。

1 完善被调试终端的KGDB

远端的 gdb 连上 linux 的 kgdb 之后,在断点处执行单步调式(step/next)的时候,调式器并不是执行断点处的语句,而是每次都陷入到下面的代码段:

arch/arm64/kernel/entry.S:356
el1_irq:
        kernel_entry 1
        enable_dbg

社区也有人碰到这个问题,并提交了如下 patch 来修复这个问题。这个问题并不是在所有的 arm64 平台上都会碰到,patch 还在讨论并没有合进 upstream,Patch 如下:
[v3,2/4] arm64: kgdb: disable interrupts while a software step is enabled

注:至少我在Linux5.4.24中发现并没有解决这个问题,更不用说大部分嵌入式板子还用的4.x的内核。

diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index b9176b324e5a..fddbc6be3780 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -28,6 +28,7 @@ 
 
 #include <asm/debug-monitors.h>
 #include <asm/insn.h>
+#include <asm/ptrace.h>
 #include <asm/traps.h>
 
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
@@ -111,6 +112,8 @@  struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
 	{ "fpcr", 4, -1 },
 };
 
+static DEFINE_PER_CPU(unsigned int, kgdb_pstate);
+
 char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
 {
 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
@@ -200,6 +203,10 @@  int kgdb_arch_handle_exception(int exception_vector, int signo,
 		err = 0;
 		break;
 	case 's':
+		/* mask interrupts while single stepping */
+		__this_cpu_write(kgdb_pstate, linux_regs->pstate);
+		linux_regs->pstate |= PSR_I_BIT;
+
 		/*
 		 * Update step address value with address passed
 		 * with step packet.
@@ -242,11 +249,20 @@  NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
 
 static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
+	unsigned int pstate;
+
 	if (!kgdb_single_step)
 		return DBG_HOOK_ERROR;
 
 	kernel_disable_single_step();
 
+	/* restore interrupt mask status */
+	pstate = __this_cpu_read(kgdb_pstate);
+	if (pstate & PSR_I_BIT)
+		regs->pstate |= PSR_I_BIT;
+	else
+		regs->pstate &= ~PSR_I_BIT;
+
 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
 	return 0;
 }

2 配置内核

2.1 构建开发环境

source /opt/fsl-imx-xwayland/5.4-zeus/environment-setup-aarch64-poky-linux
make imx_v8_defconfig
make menuconfig

如果在make menuconfig出现如下问题,具体解决方案可以看,我就不在这里多费口舌了。

HOSTLD  scripts/kconfig/mconf
/usr/bin/ld: cannot find -lncursesw
collect2: error: ld returned 1 exit status
scripts/Makefile.host:116: recipe for target 'scripts/kconfig/mconf' failed
make[1]: *** [scripts/kconfig/mconf] Error 1
Makefile:567: recipe for target 'menuconfig' failed
make: *** [menuconfig] Error 2

注:source /opt/fsl-imx-xwayland/5.4-zeus/environment-setup-aarch64-poky-linux为我yocto编译下载后的交叉编译工具链的安装位置

2.2设置内核选项

配置内核KGDB选项
在这里插入图片描述

配置dwmac-imx编译为模块

注:这个是我用于调试的模块,其他模块类似的操作

在这里插入图片描述

2.3 修改对应模块的优化等级

stmac目录下的Makefile添加如下编译优化等级
在这里插入图片描述
O1优化等级会出现如下小问题,不过还好,凑活着用
在这里插入图片描述

我想修改为O0,但是编译不成功,只能用O1了
注:这个地方因勉强可以用,就没有深究下去
在这里插入图片描述

2.4 内核编译

make -j 8

3 代码修改记录总计

<sazczmh 10:27:28@linux-imx>$git log --stat -p
commit 56e89cdadaac0ded943486912afc135b7dc46cf5 (HEAD -> imx_5.4.24_2.1.0)
Author: sazczmh <zmhzc@tju.edu.cn>
Date:   Sat Aug 8 10:24:36 2020 +0800

    Modify the dwmac module compilation aptimization level to O1
---
 drivers/net/ethernet/stmicro/stmmac/Makefile | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 413d2104948d..91d55b92ce88 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
-# Modify the module compilation aptimization level to O0
-EXTRA_CFLAGS   += -O0
+# Modify the module compilation aptimization level to O1
+EXTRA_CFLAGS   += -O1
 
 obj-$(CONFIG_STMMAC_ETH) += stmmac.o
 stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \

commit 550c7b51c425418b8122a834e5236592537a22f9
Author: sazczmh <zmhzc@tju.edu.cn>
Date:   Sat Aug 8 09:43:29 2020 +0800

    Modify the code warning!
---
 arch/arm64/kernel/kgdb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index dfe6ffcd71f6..52f5010c1166 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -269,7 +269,7 @@ static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
     else
         regs->pstate &= ~PSR_I_BIT;
 
-       kgdb_handle_exception(1, SIGTRAP, 0, regs);
+    kgdb_handle_exception(1, SIGTRAP, 0, regs);
        return DBG_HOOK_HANDLED;
 }
 NOKPROBE_SYMBOL(kgdb_step_brk_fn);

commit c92c9abd0aebdc70f9a97f670cfa61cc1fa8e96e
Author: sazczmh <zmhzc@tju.edu.cn>
Date:   Sat Aug 8 09:35:38 2020 +0800

    To reduce unnecessary compilation warnings, only module compilation optomization level is O0
---
 Makefile                                     | 2 +-
 drivers/net/ethernet/stmicro/stmmac/Makefile | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 02191761c23f..c32c78cf2fe5 100644
--- a/Makefile
+++ b/Makefile
@@ -700,7 +700,7 @@ KBUILD_CFLAGS       += $(call cc-disable-warning, format-overflow)
 KBUILD_CFLAGS  += $(call cc-disable-warning, address-of-packed-member)
 
 ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
-KBUILD_CFLAGS += -O1
+KBUILD_CFLAGS += -O2
 else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
 KBUILD_CFLAGS += -O3
 else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index ae223ec1b754..413d2104948d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -1,4 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
+# Modify the module compilation aptimization level to O0
+EXTRA_CFLAGS   += -O0
+
 obj-$(CONFIG_STMMAC_ETH) += stmmac.o
 stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
              chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \

commit 11eb493c15b271f00d982985dedca75e98145734
Author: sazczmh <zmhzc@tju.edu.cn>
Date:   Sat Aug 8 09:21:53 2020 +0800

    arm64, kgdb debug: Disable interrupts while a software step is enable
---
 arch/arm64/kernel/kgdb.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c
index 43119922341f..dfe6ffcd71f6 100644
--- a/arch/arm64/kernel/kgdb.c
+++ b/arch/arm64/kernel/kgdb.c
@@ -19,6 +19,11 @@
 #include <asm/insn.h>
 #include <asm/traps.h>
 
+#include <asm/ptrace.h>
+
+static DEFINE_PER_CPU(unsigned int, kgdb_pstate);
+
+
 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
        { "x0", 8, offsetof(struct pt_regs, regs[0])},
        { "x1", 8, offsetof(struct pt_regs, regs[1])},
@@ -206,7 +211,10 @@ int kgdb_arch_handle_exception(int exception_vector, int signo,
                err = 0;
                break;
        case 's':
-               /*
+        
+        __this_cpu_write(kgdb_pstate, linux_regs->pstate);
+        linux_regs->pstate |= PSR_I_BIT;
+        /*
                 * Update step address value with address passed
                 * with step packet.
                 * On debug exception return PC is copied to ELR
@@ -249,8 +257,17 @@ NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
 
 static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
 {
-       if (!kgdb_single_step)
-               return DBG_HOOK_ERROR;
+    unsigned int pstate;
+
+    if (!kgdb_single_step)
+        return DBG_HOOK_ERROR;
+    kernel_disable_single_step();
+
+    pstate = __this_cpu_read(kgdb_pstate);
+    if (pstate & PSR_I_BIT)
+        regs->pstate |= PSR_I_BIT;
+    else
+        regs->pstate &= ~PSR_I_BIT;
 
        kgdb_handle_exception(1, SIGTRAP, 0, regs);
        return DBG_HOOK_HANDLED;

这个是截图,比较好看些
在这里插入图片描述

在这里插入图片描述

4 文件共享

开发板与PC的文件传输是通过NFS,方便进行开发,具体可以参考【Linux笔记】挂载网络文件系统

我的共享文件夹为~/imx8mp_evk_nfs/,共享模块文件,使用如下命令即可,比较方便

cp ~/linux-imx/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.ko ~/imx8mp_evk_nfs/

注:文件夹挂载之前不要在这个文件夹,否则会没法刷新cd /;cd /mnt 即可解决。
注:我的配置环境是开发板与PC的网络是通过一个路由器进行通信的,网线直连会有所不同。

5 串口复用

为了调试方便使用agent-proxy即可,需要进行编译安装

使用如下命令可以将ttyUSB2复用为两个端口,方便调试。

./agent-proxy  5550^5551 0 /dev/ttyUSB2,115200 -s003

其中一个可以用如下命令连接开发板,与板子进行通信

telnet localhost 5550

另一个端口用于KGDB调试使用

在这里插入图片描述
:这个具体原理我没有深究,大概就是将串口的读取发送数据,通过localhost虚拟出来两个端口来进行使用,很容易上手。
:这个/dev/ttyUSB2需要具体情况具体设置,对于imx8mp来说是从USB插入开始,识别的第三个串口,具体可以用demsg查看

6 GDB优化

Ubuntu18自带的GDB不太好使,调试不方便,需要gdb的界面增强版CGDB,增加了语法高亮等一系列小功能,可以提高调试效率。

使用如下命令即可进行安装

sudo apt install cgdb

下面是我cgdb的调试界面,相对于默认的gdb单色调试界面,这个语法高亮非常实用。
在这里插入图片描述

注:我也尝试使用eclipse进行调试,可是存在着一些问题,因此就先不说那个了。

7 开发板配置

开发板的连接是通过如下命令进行的

./agent-proxy  5550^5551 0 /dev/ttyUSB2,115200 -s003
telnet localhost 5550

使用如下命令即可进入gdb命令行,然后再执行kgdb即可等待主机的连接

mount -t nfs -o nolock,vers=4 192.168.3.5:/home/sazczmh/imx8mp_evk_nfs /mnt

echo ttymxc1 > /sys/module/kgdboc/parameters/kgdboc
echo g  >  /proc/sysrq-trigger

注:这个192.168.3.5:/home/sazczmh/imx8mp_evk_nfs为我的主机共享文件夹,IP以及目录需要根据具体情况进行修改。
注:ttymxc1为imx8mp的调试串口,不同的把板子可能需要进行相应的修改。

8 主机配置

执行如下命令解析vmlinux,准备开始调试

cd ~/linux-imx
cgdb -d gdb-multiarch vmlinux

设置架构为aarch64,再加载被调试模块的信息

set architecture aarch64

add-symbol-file drivers/net/ethernet/stmicro/stmmac/dwmac-imx.ko 0xffff8000090a0000

注:set architecture aarch64的目的是防止出现Remote ‘g’ packet reply is too long (expected 168 bytes, got 788 bytes)这个错误,也可以利用交叉编译工具链的gdb工具,就不会出现这个问题,后续文章会略有涉及。
注:0xffff8000090a0000这个可以提前通过insmod加载对应模块,再通过cat /proc/modules 可以查看,查看之后注意要卸载rmmod。

现在要连接开发板,设置对应的断点,c开始执行调试

target remote localhost:5551
b stmmac_dvr_probe
c

开发板同时要加载模块,触发断点,就可以进行单步调试了。

参考博客

  • ARM64 的 Linux 内核 kgdb/kdb调试
    这个讲解的很全面具体,本文就是大部分是参考这个文章,然后根据个人需求进行魔改优化的。
  • GDB调试利器
    从火哥这个文章知道CGDB这个好东西,对于高效率调试非常有帮助,后面还会有关于它的文章。

注:个人能力有限,欢迎批评指正。



原创不易,严禁剽窃!

在这里插入图片描述

欢迎大家关注我创建的微信公众号——小白仓库
原创经验资料分享:包含但不仅限于FPGA、ARM、RISC-V、Linux、LabVIEW等软硬件开发,另外分享生活中的趣事以及感悟。目的是建立一个平台记录学习过的知识,并分享出来自认为有用的与感兴趣的道友相互交流进步。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值