环境:
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正常运行之后, 开发板的打印信息也不再乱码了

在这里插入图片描述

Logo

更多推荐