linux驱动之调试技巧--- 应用程序远程gdb+vscode调试应用程序, 串口kgdboc调试.ko驱动程序
gdb+vscode图形化调试模式串口kgdboc调试.ko模块的结合联动调试
环境:
Ubuntu: Ubuntu 22.04.1
开发板: imx6ull
linux内核版本: Linux4.9.88
虚拟机: vmware15
交叉编译工具gcc版本: 4.9.4 (Linaro GCC 4.9-2017.01)
arm-linux-gdb版本: gdb (Linaro_GDB-2017.01) 7.10.1.20160210
先决条件
开发板 虚拟机 PC 可互通网络 交叉编译环境已经搭建好
开发板IP: 192.168.31.178
虚拟机IP: 192.168.31.158
PC机IP:192.168.31.139
使用kgdboc模式(串口连接)调试驱动, 远程gdb调试(网口连接)应用程序
本文操作能达到的效果 :
在linux中使用vscode进行图形化调试开发板的应用程序, 同时能对驱动代码进行断点调试:
应用程序远程gdb图形化调试环境搭建
可实现在vscode中直接对应用程序和驱动程序的联调.
搭建环境:
Makefile:
需要对应用程序的编译加上编译选项 -g
对驱动程序的编译加上 EXTRA_CFLAGS +=-g
搭建应用程序的图形化调试环境:
移植GDB
如果交叉编译工具链有 arm-linux-gdb 和 gdbserver可以直接用 不需要编译源码
获取gdb源码:
gdb官网上获取源码,地址为 http://www.gnu.org/software/gdb/download/
- 编译 gdb
配置项如下:
–target:目标机交叉编译器前缀,也就是你所使用的交叉编译器前缀,比如在本教程中就
设置为 arm-linux-gnueabihf。
–host:指定编译后的程序在哪里运行,编译 gdb的时候就需用设置,因为我们是需要在 PC
上运行的,编译 gdbserver的时候就要设置为 arm-linux。
–prefix:指定安装目录。
创建一个名为“gdb”的文件夹,用来保存编译后的 gdb和 gdbserver,路径自行选择。
mkdir build //在 gdb源码下新建 build目录
cd build //进入到刚刚创建的 build目录下
../configure --target=arm-linux-gnueabihf --prefix=/home/yu/gdb
make //编译
make install //安装
不出意外的话在~/gdb目录下会有 需要arm-linux-gnueabihf-gdb 和 gdbserver
- 运行./arm-linux-gnueabihf-gdb
没问题, 如果运行不了,更换交叉工具链再进行源码编译
- 将gdbserver放到开发板的/bin 目录中
开发板运行命令 gdbserver --version
-
配置vscode
安装远程调试插件"Remote Development"
点击“调试”->“添加配置”,然后选择“C++(GDB/LLDB)
点击之后,当前文件夹会新建一个名为“launch.json” 的文件,此文件会存放在.vscode目录下 -
修改launch.json的内容:
{
…
5 “version”: “0.2.0”,
6 “configurations”: [
7 {
8 “name”: “gdbtest”, //填写应用程序的名字
9 “type”: “cppdbg”,
10 “request”: “launch”,
11 “program”: “
w
o
r
k
s
p
a
c
e
F
o
l
d
e
r
/
g
d
b
t
e
s
t
"
,
/
/
应
用
程
序
的
路
径
12
"
a
r
g
s
"
:
[
]
,
13
"
s
t
o
p
A
t
E
n
t
r
y
"
:
f
a
l
s
e
,
14
"
c
w
d
"
:
"
{workspaceFolder}/gdbtest", //应用程序的路径 12 "args": [], 13 "stopAtEntry": false, 14 "cwd": "
workspaceFolder/gdbtest",//应用程序的路径12"args":[],13"stopAtEntry":false,14"cwd":"{workspaceFolder}”,
…
25 “miDebuggerPath”:
“/home/yu/ToolChain/bin/arm-linux-gnueabihf-gdb”, //指定刚刚编译出来的arm-linux-gnueabihf-gdb的路径
26 “miDebuggerServerAddress”: “192.168.31.178:2001” //填写servergdb的ip地址,端口自定义
27
28 }
29 ]
30 }
- 测试
开发板运行测试用例gdbtest(gdbtest自行准备)
运行 gdbserver 192.168.31.158:2001 gdbtest进入等待远程连接状态
vscode进入代码打上断点直接F5进行调试
成功运行
至此调试应用程序的环境已经搭建完毕~
构建出支持调试的内核镜像
- make menuconfig 中搜索以下的选项
有些可能在自己的开发板上没有, 直接跳过即可, 笔者开发板仅设置了
1, CONFIG_KGDB=y (重要)
Kernel hacking —>KGDB:kernel debugger
2, CONFIG_DEBUG_INFO = y
Kernel hacking —>Compile-time checks and compiler options—>Compile the kernel with debug info
make zImage 编译出内核
更换掉开发板中的内核
-
在uboot中修改启动参数(要根据自身开发板情况进行修改, 不能盲目跟从复制)
查看uboot环境变量(这里都是开发板厂商配置的环境变量, 需要稍作修改)
目的对bootargs环境变量添加kgdboc指令
将所有环境变量复制出来 搜索以下bootargs变量在哪里被用过
由于板卡是mmc启动模式, mmcargs变量会被调用, 在这里加上kgdboc=${console},${baudrate}
表明kgdb使用的串口名和波特率 -
在Ubuntu中搭建直连开发板环境
需要将usb从主机转移到ubuntu中
安装 minicom
sudo apt install minicom
将开发板用串口连接到Ubuntu中(vmware右下角有提示)
查看 usb设备文件
ls /dev/tty*
已有 ttyUSB0设备
修改设备权限
sudo chmod 777 ttyUSB0
设置minicom
sudo minicom -s
运行命令 minicom 可进入开发板
Ubuntu直连开发板完成
- 开发板进入内核调试模式
在前面的步骤已经设置好了 kgdboc参数
现在加载需要调试的ko驱动程序
insmod hello_drv.ko
查看在开发板中模块信息
cat /proc/modules
在Ubuntu终端中使用
arm-linux-gnueabihf-objdump -h hello_drv.ko
查看驱动文件头信息
会跳出一大串地址信息, 需要关注
.text
.bss
.data
一切准备就绪 开发板中启用命令 (如果这一步骤没成功 是 uboot设置的启动参数 bootargs 没设置 kgdboc)
echo g > /proc/sysrq-trigger
进入KGDB调试模式 等待GDB连接
- Ubuntu终端使用GDB连接KGDB
我们使用vscode中的终端来完成, 更方便查阅代码
打开vscode, 调出终端窗口 进入驱动程序所在目录
运行 命令
yu@yu$ arm-linux-gnueabihf-gdb
进入gdb调试模式
设置波特率
(gdb) set serial baud 115200
连接至串口与kgdb通信
(gdb) target remote /dev/ttyUSB0
使用add-symbol-file导入ko文件符号
(gdb) add-symbol-file hello_drv.ko 0x7f000034 -s .data 0x7f00074c -s .bss 0x7f000a24
这些值的计算方式如下:
add-symbol-file *.ko text_addr –s .section0 section_addr0 -s .section1 section_addr1
Text_addr = install_addr + file_off
.section_addr0 = install_addr + file_off
如:.data 段
Section_addr = install_addr + file_off = 0x7f000000 + 0x74c = 0x7f00074c
此时输入指令 list 应该是能看到已经进入了 自己写的驱动程序
输入 b 30 指令 设置断点
输入 c指令 开始 运行
- 一切就绪开始 应用程序 与 驱动的联调
在pc机使用网口连接 开发板 可以发现开发板已经能正常操作了
按之前的步骤启动gdbserver
不出意外的话 当应用程序运行到第36行read函数时, 驱动程序的断点会被击中
果然正如我所料 断点击中, 此时就可以用gdb的命令来调试驱动程序了
- 串口无法使用, 无法查看打印信息
此时已能正常调试, 但是串口被kgdb占用, 同时内核也在同一个串口输出数据, 导致了串口持续乱码
解决这个问题要用到工具叫 agent-proxy
下载地址 : https://git.kernel.org/cgit/utils/kernel/kgdb/agent-proxy.git/
原理就是 将原来的串口 映射成两个, 让kgdb的输出和内核的输出走不同的映射串口.
在开发板操作echo g > /proc/sysrq-trigger命令进入等待连接状态之后
我们要将minicom的终端关闭.
输入命令 agent-proxy 5550^5551 0 /dev/ttyUSB0,115200
这个终端不能关闭
将/dev/ttyUSB0 映射5550 和 5551
新开启一个终端, 输入命令telnet localhost 5550 这个终端就进入了开发板
Ubuntu在导入文件头信息 add-symbol-file之后 , 输入命令target remote localhost:5551去连接另一个映射
只要终端的gdb正常运行之后, 开发板的打印信息也不再乱码了
更多推荐
所有评论(0)