跳到主要内容

SDK 应用调试指南

SDK 烧录到开发板之后需要进行开发调试,本文将介绍在开发调试中常用的工具,方便开发流程。一般开发环境如下图所示,PC 与开发板通过串口线与 USB 线连接。通过串口线访问开发板控制终端,通过 USB 执行下载烧录、ADB 等功能。

image-20241126094352689

概述

调试工具简介

V861 SDK 提供了多种调试工具,各有特点和适用场景。下表帮助您快速选择合适的调试工具:

工具功能概述学习难度推荐使用场景
ADB命令行交互、文件传输、远程执行★☆☆ 低日常开发、快速验证、简单调试
GDB断点调试、单步执行、变量查看★★★ 高深入分析程序逻辑、复杂问题定位
VSCode图形化调试环境、断点、变量监视★★☆ 中大型项目开发、日常开发首选
Coredump事后分析崩溃问题、内存转储★★☆ 中无法实时调试的场景、崩溃分析

章节导航

  • 初次使用:建议从「使用 ADB 辅助调试」开始,熟悉基本的命令行操作
  • 深入调试:阅读「使用 GDB 远程调试」,掌握命令行调试技巧
  • 提升效率:配置「使用 VSCode 开发调试」,享受图形化调试体验
  • 崩溃分析:学习「使用 Coredump 文件调试」,处理无法实时调试的问题

使用 ADB 辅助调试

工具简介

ADB(Android Debug Bridge)原本是 Android 平台的调试工具,V861 SDK 将其移植到了 Linux 平台。通过 ADB,您可以:

  • 远程执行命令:无需串口,直接在 PC 上执行开发板命令
  • 文件传输:方便地在 PC 和开发板之间传输文件
  • 端口转发:为 GDB 等工具提供网络通道
  • 系统控制:重启设备、进入烧写模式等

前置条件

执行 m menuconfig,勾选 ADB 软件包:

Allwinner  --->
USB --->
<*> adbd................................................. adbd for Tina Linux

image-20260320140626603

环境搭建

在使用 ADB 之前,需要在 PC 上搭建 ADB 环境。

Windows 环境:

  1. 下载 ADB 工具包:SDK 平台工具版本说明
  2. 解压到任意目录(如 C:\platform-tools
  3. 将该目录添加到系统环境变量 PATH 中
  4. 打开命令提示符,输入 adb version 验证安装

Linux 环境:

# Ubuntu/Debian
sudo apt-get install android-tools-adb

# 验证安装
adb version

更多详细信息请参考 Android 调试桥官方文档

连接方式

USB 连接

USB 连接是最简单、最稳定的连接方式。

步骤:

  1. 开发板烧录固件后,使用 USB 线连接 PC 和开发板
  2. 在 PC 命令行中检查连接状态:
adb devices

image-20241125130559362

  1. 看到设备列表后,进入 ADB 控制台:
adb shell

image-20241125130654122

网络连接

网络连接适用于开发板与 PC 距离较远,或需要无线调试的场景。

步骤:

(1)开发板连接网络

开发板通过串口连接,输入命令搜索 Wi-Fi 网络:

wifi -s

image-20241125131103199

搜索到目标网络后,连接:

wifi -c <SSID> <密码>

连接成功后,使用 ifconfig 查看分配的 IP 地址:

image-20241125131745250

(2)配置开发板无线 ADB

设置 ADB 监听端口(默认使用 5555):

export ADB_TRANSPORT_PORT=5555

重启 ADB 服务:

kill $(pgrep adbd) && adbd -D &

(3)PC 端连接

使用 IP 地址和端口连接:

adb connect <IP>:5555

image-20241125133900839

(4)默认开启网络 ADB(可选)

如需开机自动启动网络 ADB,修改文件 openwrt/openwrt/package/subpackage/allwinner/usb/adbd/adbd.init,取消 ADB_TRANSPORT_PORT 的注释:

image-20241125134125045

常用命令详解

设备管理

命令说明示例
adb devices列出已连接设备adb devices
adb connect <ip>:<port>网络连接设备adb connect 192.168.1.100:5555
adb disconnect断开网络连接adb disconnect
adb kill-server终止 ADB 服务adb kill-server
adb start-server启动 ADB 服务adb start-server

文件传输

命令说明示例
adb push <local> <remote>推送文件到设备adb push sample_virvi /mnt/extsd
adb pull <remote> <local>从设备拉取文件adb pull /mnt/extsd/log.txt ./

示例:推送可执行文件和配置文件到开发板

adb push sample_virvi /mnt/extsd
adb push sample_virvi.conf /mnt/extsd

远程执行命令

命令说明示例
adb shell进入交互式 Shelladb shell
adb shell <command>执行单条命令adb shell ls /mnt/extsd

示例:查看开发板文件列表

adb shell ls -la /mnt/extsd

系统控制

命令说明示例
adb reboot重启设备adb reboot
adb reboot efex进入烧写模式adb reboot efex
adb reboot recovery进入恢复模式adb reboot recovery

端口转发

命令说明示例
adb forward tcp:<local> tcp:<remote>端口转发adb forward tcp:2241 tcp:2241

常见问题排查

Q: adb devices 看不到设备?

可能原因及解决方案:

  1. USB 线问题:更换 USB 线或换一个 USB 接口
  2. 驱动问题(Windows):安装 ADB 驱动,或使用「设备管理器」手动安装驱动
  3. ADB 服务问题:尝试重启 ADB 服务
    adb kill-server
    adb start-server
    adb devices
  4. 开发板 ADB 未启动:检查开发板是否正确烧录固件,ADB 服务是否运行

Q: 网络连接失败?

可能原因及解决方案:

  1. IP 地址错误:确认开发板 IP 地址正确,使用 ifconfig 验证
  2. 端口未开放:确认开发板已执行 export ADB_TRANSPORT_PORT=5555 并重启 adbd
  3. 网络不通:使用 ping 测试网络连通性
  4. 防火墙阻止:检查 PC 或网络防火墙设置

Q: 权限被拒绝?

解决方案:

Linux 环境下可能需要配置 udev 规则:

# 创建 udev 规则文件
sudo vim /etc/udev/rules.d/51-android.rules

# 添加以下内容(vendor ID 根据实际情况修改)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666"

# 重载规则
sudo udevadm control --reload-rules
sudo udevadm trigger

使用远程 GDB 辅助调试

GDB 简介

什么是 GDB?

GDB(GNU Debugger)是 GNU 项目开发的调试器,支持多种编程语言(C/C++、Go、Rust 等)。它可以:

  • 启动程序并指定任何可能影响其行为的参数
  • 在指定条件下使程序停止
  • 检查程序停止时发生了什么
  • 修改程序中的内容以便纠正错误

为什么嵌入式需要远程调试?

在嵌入式开发中,目标设备(开发板)资源有限:

  • 内存有限:无法运行完整的 GDB
  • 存储有限:无法存储调试符号信息
  • 性能受限:调试会严重影响系统性能

因此,采用「GDB Server + GDB Client」的架构:

┌─────────────────┐                    ┌─────────────────┐
│ PC Side │ │ Board Side │
│ │ │ │
│ ┌───────────┐ │ Network │ ┌───────────┐ │
│ │ GDB │◄─┼────────────────────┼──│ GDB Server│ │
│ │ (Client) │ │ │ │ │ │
│ └───────────┘ │ │ └───────────┘ │
│ │ │ │ │
│ Debug Symbols │ │ Target Program │
│ Source Code │ │ │
└─────────────────┘ └─────────────────┘

GDB Server 运行在开发板上,体积小、资源占用少;GDB Client 运行在 PC 上,拥有完整的调试能力。

前置条件

编译调试信息

要让 GDB 正常工作,需要编译带调试信息的程序。

步骤:

  1. 编辑 openwrt/package/allwinner/eyesee-mpp/middleware/Makefile,在 FLAGS 中增加 -g 选项:
CFLAGS="-I -fstack-protector $(TARGET_CFLAGS) -g" \
CXXFLAGS="-I -fstack-protector $(TARGET_CXXFLAGS) -g" \
CPPFLAGS="-I -fstack-protector $(TARGET_CPPFLAGS) -g" \

image-20241125193813049

  1. 重新编译 MPP:
cleanmpp && mkmpp

说明-g 选项告诉编译器在可执行文件中包含调试信息(如变量名、函数名、源代码行号等)。没有调试信息,GDB 只能进行汇编级别的调试。

配置 GDB Server

进入 menuconfig 勾选 gdbserver

Development  --->
<*> gdbserver................................. Remote server for GNU Debugger

image-20241125134554181

端口转发配置

ADB 端口转发

由于 GDB Client 和 GDB Server 通过网络通信,而开发板通常没有公网 IP,需要使用 ADB 端口转发。

原理图:

┌────────────────┐        USB         ┌────────────────┐
│ PC │◄──────────────────►│ Board │
│ │ │ │
│ localhost │ adb forward │ localhost │
│ :2241 ───────┼────────────────────┼──► :2241 │
│ │ │ │ │
│ │ │ gdbserver │
│ │ │ listen 2241 │
└────────────────┘ └────────────────┘

命令格式:

adb forward tcp:<local_port> tcp:<device_port>
  • local_port:PC 端监听端口
  • device_port:开发板端监听端口

示例:转发端口 2241

adb forward tcp:2241 tcp:2241

image-20241125140103824

转发到编译服务器(可选)

在企业开发环境中,编译通常在远程服务器进行,需要额外一层端口转发。

拓扑图:

┌──────────────┐      SSH Tunnel      ┌──────────────┐      ADB Forward     ┌──────────────┐
│ Build Server │◄────────────────────►│ PC │◄────────────────────►│ Board │
│ │ │ │ │ │
│ GDB │ PuTTY/SSH │ adb │ USB │ gdbserver │
│ :2241 ◄─────┼──────────────────────┼─── :2241 ◄───┼──────────────────────┼──► :2241 │
│ │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘

配置步骤:

  1. 打开 PuTTY,配置编译服务器地址
  2. 点击 Connection → SSH → Tunnels
  3. 配置端口转发:

image-20241125144408930

  1. 按图中顺序配置:

image-20241125144737214

  1. 点击 Open 建立连接

此后,在编译服务器上访问 localhost:2241 即可连接开发板的 GDB Server。

连接与调试

启动 GDB Server

在开发板上启动 GDB Server:

gdbserver --multi 0:2241 &

image-20241126095639365

image-20241125163756130

参数说明

  • --multi:启用扩展模式,允许 GDB 控制程序加载和运行
  • 0:2241:监听所有网络接口的 2241 端口
  • &:后台运行

使用 GDB 连接

(1)启动 GDB

进入工具链目录(根据使用的 libc 选择):

cd prebuilt/rootfsbuilt/riscv/Xuantie-900-gcc-linux-6.6.36-musl32-x86_64-V3.3.0/bin

启动 GDB:

./riscv32-unknown-linux-musl-gdb

image-20260320150557277

(2)加载被调试程序

(gdb) file ../../../../../platform/allwinner/eyesee-mpp/middleware/sun252iw1/sample/bin/sample_virvi

image-20260320150918570

说明file 命令加载可执行文件的符号表,使 GDB 能够将机器码映射到源代码。

(3)配置动态库搜索路径

GDB 需要知道动态库的位置才能加载符号:

(gdb) set sysroot ../../../../../out/v861/bga_perf1/openwrt/staging_dir/target/root-v861-bga_perf1/
(gdb) set solib-search-path ../../../../../out/v861/bga_perf1/openwrt/staging_dir/target/root-v861-bga_perf1/usr/lib
(gdb) info sharedlibrary

image-20260320151126486

说明

  • sysroot:设置库文件的根目录前缀
  • solib-search-path:设置库文件的搜索路径
  • info sharedlibrary:显示已加载的共享库信息

(4)连接 GDB Server

(gdb) target extended-remote :2241

image-20260320151352653

说明extended-remote 模式允许 GDB 控制程序加载和运行,比普通的 remote 模式功能更强大。

(5)推送可执行文件

将编译好的可执行文件推送到开发板:

adb push sample_virvi /mnt/extsd
adb push sample_virvi.conf /mnt/extsd

在 GDB 中设置远端执行文件:

(gdb) set remote exec-file /mnt/extsd/sample_virvi

image-20241125155327383

断点操作详解

设置断点

按函数名设置断点:

(gdb) break main

image-20241125201653834

按文件和行号设置断点:

(gdb) break sample_virvi/sample_virvi.c:1113

image-20241125201705178

按条件设置断点:

(gdb) break sample_virvi/sample_virvi.c:1113 if pContext->mSaveBufMgrConfig.mSavePicDev >= 0

image-20241125201716441

只有当条件满足时,程序才会暂停。

按内存地址设置断点:

(gdb) break *0x0001e136

image-20241125201724814

适用于没有源代码时的调试。

管理断点

查看所有断点:

(gdb) info breakpoints

image-20241125201735291

启用断点:

(gdb) enable 1

image-20241125201755041

禁用断点:

(gdb) disable 1

image-20241125201806118

删除断点:

(gdb) delete 1

image-20241125201816607

单步调试详解

启动程序

(gdb) run -path /mnt/extsd/sample_virvi.conf

程序将在第一个断点处暂停。

查看代码

(gdb) list

image-20241125201859164

继续执行

(gdb) continue

image-20241125201909350

程序将继续执行,直到下一个断点或程序结束。

单步执行

next(不进入函数):

(gdb) next

执行当前行,如果当前行是函数调用,则执行完整个函数。

step(进入函数):

(gdb) step

执行当前行,如果当前行是函数调用,则进入函数内部。

变量查看详解

查看变量值

(gdb) print pContext->mSaveBufMgrConfig.mSavePicDev

image-20241125201944333

查看局部变量

(gdb) info locals

image-20241125201956546

查看结构体内容

(gdb) p *pContext

image-20241125195409423

GDB 命令速查表

功能命令说明
断点操作
设置断点(函数)break main在函数入口设置断点
设置断点(行号)break file.c:100在指定文件的指定行设置断点
设置断点(条件)break file.c:100 if var > 0条件断点
设置断点(地址)break *0x12345678在内存地址设置断点
查看断点info breakpoints显示所有断点
启用断点enable 1启用编号为 1 的断点
禁用断点disable 1禁用编号为 1 的断点
删除断点delete 1删除编号为 1 的断点
执行控制
启动程序run [args]启动程序执行
继续执行continue继续执行到下一个断点
单步(不进入)next执行一行,不进入函数
单步(进入)step执行一行,进入函数
执行到指定行until 100执行到第 100 行
变量查看
打印变量print var打印变量值
打印结构体print *ptr打印指针指向的结构体
查看局部变量info locals显示当前函数的局部变量
查看参数info args显示当前函数的参数
查看调用栈bt显示函数调用栈
其他
查看代码list显示当前位置的源代码
查看线程info threads显示所有线程
切换线程thread 2切换到线程 2
退出 GDBquit退出调试

常见问题排查

Q: 连接 GDB Server 超时?

错误信息:

Remote connection closed
could not connect: Connection timed out.

排查步骤:

  1. 检查开发板 gdbserver 是否运行:ps | grep gdbserver
  2. 检查端口转发是否正确:adb forward --list
  3. 检查防火墙设置
  4. 尝试重新建立连接:
    adb kill-server
    adb start-server
    adb forward tcp:2241 tcp:2241

Q: 符号表加载失败?

错误信息:

Reading symbols from /lib/libc.so...
(no debugging symbols found)

解决方案:

  1. 确认编译时添加了 -g 选项
  2. 检查 sysrootsolib-search-path 路径是否正确
  3. 使用 info sharedlibrary 检查库加载状态

Q: 动态库找不到?

错误信息:

Cannot find new threads: generic error

解决方案:

确保 sysroot 指向正确的根文件系统路径:

(gdb) set sysroot /path/to/rootfs

使用 VSCode 开发调试

VSCode 简介

Visual Studio Code(VSCode)是微软开发的开源代码编辑器,具有以下优势:

  • 跨平台:支持 Windows、Linux、macOS
  • 插件丰富:拥有庞大的插件生态系统
  • 调试功能强大:支持断点、变量监视、调用栈查看
  • 远程开发:支持 SSH 远程连接服务器开发

对于嵌入式开发,VSCode 可以替代命令行 GDB,提供更直观的图形化调试体验。

前置条件

编译调试信息

要让 VSCode 调试正常工作,需要编译带调试信息的程序。

步骤:

  1. 编辑 openwrt/package/allwinner/eyesee-mpp/middleware/Makefile,在 FLAGS 中增加 -g 选项:
CFLAGS="-I -fstack-protector $(TARGET_CFLAGS) -g" \
CXXFLAGS="-I -fstack-protector $(TARGET_CXXFLAGS) -g" \
CPPFLAGS="-I -fstack-protector $(TARGET_CPPFLAGS) -g" \

image-20241126100530027

  1. 重新编译 MPP:
cleanmpp && mkmpp

GDB 环境配置

确保已完成「使用远程 GDB 辅助调试」章节中的以下步骤:

  • GDB Server 已配置并运行
  • ADB 端口转发已建立
  • 可执行文件已推送到开发板

环境配置

安装 VSCode

从官网下载安装:https://code.visualstudio.com/

配置远程开发(可选)

如果 SDK 在远程服务器上,需要安装 Remote-SSH 扩展:

  1. 在 VSCode 中按 Ctrl+Shift+X 打开扩展面板
  2. 搜索并安装 Remote - SSH
  3. F1,输入 Remote-SSH: Connect to Host 连接服务器

更多详情参考 VSCode 远程 SSH 文档

安装 C/C++ 扩展

  1. 点击扩展图标
  2. 搜索 C/C++
  3. 安装 Microsoft 的 C/C++ 扩展

image-20241126095959972

扩展地址:https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools

launch.json 配置详解

创建 launch.json

  1. 点击调试图标
  2. 点击「创建 launch.json 文件」

image-20241126100233489

  1. 选择调试器类型(任意选择一个即可)

image-20241126100250522

配置内容

以下是完整的 launch.json 配置(以调试 sample_virvi 为例):

{
"version": "1.0.0",
"configurations": [
{
"name": "(gdb) Launch sample_virvi",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/platform/allwinner/eyesee-mpp/middleware/sun252iw1/sample/sample_virvi/sample_virvi",
"args": [
"-path",
"/mnt/extsd/sample_virvi.conf"
],
"symbolLoadInfo": {
"loadAll": true,
"exceptionList": ""
},
"additionalSOLibSearchPath": "${workspaceFolder}/out/v861/bga_perf1/openwrt/staging_dir/target/root-v861-bga_perf1;${workspaceFolder}/out/v861/bga_perf1/openwrt/staging_dir/target/root-v861-bga_perf1/usr/lib",
"stopAtEntry": true,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "${workspaceFolder}/prebuilt/rootfsbuilt/riscv/Xuantie-900-gcc-linux-6.6.36-musl32-x86_64-V3.3.0/bin/riscv32-unknown-linux-musl-gdb",
"miDebuggerServerAddress": "localhost:2241",
"useExtendedRemote": true,
"postRemoteConnectCommands": [
{
"description": "Set remotetimeout for gdb",
"text": "set remotetimeout 20",
"ignoreFailures": true
},
{
"description": "Set remote exec-file for gdb",
"text": "set remote exec-file /mnt/extsd/sample_virvi",
"ignoreFailures": false
},
{
"description": "Set sysroot for gdb",
"text": "set sysroot ${workspaceFolder}/out/v861/bga_perf1/openwrt/staging_dir/target/root-v861-bga_perf1",
"ignoreFailures": false
},
{
"description": "Set solib-search-path for gdb",
"text": "set solib-search-path ${workspaceFolder}/out/v861/bga_perf1/openwrt/staging_dir/target/root-v861-bga_perf1/usr/lib",
"ignoreFailures": false
}
],
"setupCommands": [
{
"description": "Enable pretty-printing for GDB",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set disassembly-flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}

image-20241126100359845

配置字段说明

字段说明
name配置名称,显示在调试面板中
type调试器类型,C/C++ 使用 cppdbg
request请求类型,launch 表示启动调试
program要调试的程序路径(本地带符号表的程序)
args程序运行参数
MIMode调试器模式,使用 GDB
miDebuggerPathGDB 可执行文件路径
miDebuggerServerAddressGDB Server 地址
useExtendedRemote使用扩展远程模式
postRemoteConnectCommands连接后执行的 GDB 命令

修改配置

针对不同的调试需求,需要修改以下字段:

image-20241126101247724

  • program:修改为要调试的程序路径
  • args:修改程序参数
  • miDebuggerPath:根据工具链类型修改
  • postRemoteConnectCommands 中的路径:修改为对应的板级路径

调试演示

准备工作

  1. 开发板启动 GDB Server:

    gdbserver --multi 0:2241 &
  2. PC 端配置端口转发:

    adb forward tcp:2241 tcp:2241
  3. 推送可执行文件:

    adb push sample_virvi /mnt/extsd
    adb push sample_virvi.conf /mnt/extsd

开始调试

  1. 打开源代码文件,在需要暂停的行点击左侧设置断点:

image-20241126101440137

  1. 切换到调试面板,点击「开始调试」:

image-20241126101528097

  1. 程序将在断点处暂停:

image-20241126101618274

  1. 查看调试信息:

image-20241126101744079

调试面板提供以下功能:

  • 变量:查看当前作用域的变量
  • 监视:添加表达式监视
  • 调用堆栈:查看函数调用栈
  • 线程:切换线程

常见问题排查

Q: launch.json 配置错误?

检查要点:

  1. 路径使用正斜杠 / 或双反斜杠 \\
  2. ${workspaceFolder} 表示工作区根目录
  3. JSON 格式正确(无多余逗号、引号匹配)

Q: 断点不生效?

可能原因:

  1. 编译时未添加 -g 选项
  2. 源代码与编译时的代码不一致
  3. 优化级别过高(尝试添加 -O0

Q: 无法连接 GDB Server?

排查步骤:

  1. 检查 GDB Server 是否运行
  2. 检查端口转发是否正确
  3. 检查 miDebuggerServerAddress 配置是否正确

使用 Coredump 文件调试

Coredump 简介

什么是 Coredump?

Coredump(核心转储)是程序崩溃时操作系统生成的一个文件,它包含了程序崩溃时的内存映像、寄存器状态、堆栈信息等。通过分析 Coredump 文件,可以定位程序崩溃的原因。

工作原理

Program Crash


OS captures exception signal


Generate Coredump file (memory image + registers + stack)


Load Coredump with GDB for analysis


Locate crash cause

适用场景

  • 程序偶发性崩溃,难以复现
  • 生产环境问题分析
  • 无法使用 GDB 实时调试的场景

前置条件

编译调试信息

要让 Coredump 分析有意义,需要编译带调试信息的程序。

步骤:

  1. 编辑 openwrt/package/allwinner/eyesee-mpp/middleware/Makefile,在 FLAGS 中增加 -g 选项:
CFLAGS="-I -fstack-protector $(TARGET_CFLAGS) -g" \
CXXFLAGS="-I -fstack-protector $(TARGET_CXXFLAGS) -g" \
CPPFLAGS="-I -fstack-protector $(TARGET_CPPFLAGS) -g" \
  1. 重新编译 MPP:
cleanmpp && mkmpp

配置 Coredump 环境

内核配置

内核需要启用 CONFIG_COREDUMP 配置(默认已启用):

image-20241126170827676

配置 Coredump 文件大小

系统默认可能限制 Coredump 文件大小,需要取消限制:

ulimit -c unlimited

说明unlimited 表示不限制大小。也可以指定具体数值,如 ulimit -c 1000000(单位:KB)。

配置 Coredump 文件路径和格式

设置 Coredump 文件的保存路径和命名格式:

echo '/mnt/extsd/core.%e.%p' > /proc/sys/kernel/core_pattern

格式说明:

参数含义
%e程序文件名
%p进程 ID
%t时间戳
%h主机名

示例:

  • /mnt/extsd/core.%e.%p/mnt/extsd/core.sample_virvi.1234
  • /mnt/extsd/core.%e.%t/mnt/extsd/core.sample_virvi.1700000000

触发与生成 Coredump

人为触发 Coredump(测试)

为了演示 Coredump 分析流程,可以人为添加一个会导致崩溃的代码。

编辑 platform/allwinner/eyesee-mpp/middleware/sun252iw1/sample/sample_virvi/sample_virvi.c,在某个线程函数中添加空指针访问:

int *ptr = NULL;
printf("Value at ptr: %d\n", *ptr); // 访问空指针,触发段错误

image-20241126172745037

重新编译并运行,程序将崩溃并生成 Coredump 文件。

运行程序生成 Coredump

在开发板上执行:

ulimit -c unlimited
echo '/mnt/extsd/core.%e.%p' > /proc/sys/kernel/core_pattern
./sample_virvi -path sample_virvi.conf

程序崩溃后,将看到类似输出:

image-20241126173636491

检查生成的 Coredump 文件:

image-20241126173810877

使用 Coredump 定位问题

准备分析文件

将 Coredump 文件和对应的可执行文件(带调试信息)放到同一目录:

image-20241126173945428

启动 GDB 分析

进入工具链目录:

cd prebuilt/rootfsbuilt/riscv/Xuantie-900-gcc-linux-6.6.36-musl32-x86_64-V3.3.0/bin

启动 GDB 并加载程序和 Coredump 文件:

./riscv32-unknown-linux-musl-gdb ../../../../../platform/allwinner/eyesee-mpp/middleware/sun252iw1/sample/bin/sample_virvi ../../../../../platform/allwinner/eyesee-mpp/middleware/sun252iw1/sample/bin/core.sample_virvi.212

image-20241126174214913

加载符号表

如果看到库符号表加载失败的警告,需要配置库搜索路径:

(gdb) set sysroot ../../../../../out/v861/bga_perf1/openwrt/staging_dir/target/root-v861-bga_perf1/
(gdb) set solib-search-path ../../../../../out/v861/bga_perf1/openwrt/staging_dir/target/root-v861-bga_perf1/usr/lib
(gdb) info sharedlibrary

image-20241126174308619

查看崩溃位置

使用 bt(backtrace)命令查看调用栈:

(gdb) bt

image-20241126174400327

从输出可以看到崩溃发生在 sample_virvi.c 的第 565 行。

查看源代码

使用 list 命令查看崩溃位置附近的代码:

(gdb) list

image-20241126174706086

查看变量值

查看局部变量:

(gdb) info locals

image-20241126174452956

查看指针指向的内容:

(gdb) p *pContext

image-20241126174545465

查看出错原因

查看导致崩溃的指针:

(gdb) p *ptr

image-20241126174616804

可以看到 ptr 是空指针,访问空指针导致了段错误。

常见问题排查

Q: Coredump 文件未生成?

可能原因:

  1. ulimit -c 限制为 0

    • 解决:执行 ulimit -c unlimited
  2. core_pattern 配置指向管道而非文件

    • 检查:cat /proc/sys/kernel/core_pattern
    • 解决:重新配置为文件路径
  3. 磁盘空间不足

    • 检查:df -h
  4. 程序没有崩溃信号

    • 检查程序是否真的崩溃了

Q: Coredump 文件过大?

解决方案:

  1. 使用压缩:

    echo '|/bin/gzip > /mnt/extsd/core.%e.%p.gz' > /proc/sys/kernel/core_pattern
  2. 限制程序内存使用,减小 Coredump 大小

Q: GDB 分析失败?

可能原因:

  1. 可执行文件与 Coredump 不匹配

    • 确保使用同一版本的可执行文件
  2. 符号表缺失

    • 确保编译时添加了 -g 选项
  3. 库路径配置错误

    • 检查 sysrootsolib-search-path

附录

常见问题汇总

ADB 相关

问题解决方案
看不到设备检查 USB 线、驱动、ADB 服务
网络连接失败检查 IP、端口、防火墙
权限被拒绝配置 udev 规则

GDB 相关

问题解决方案
连接超时检查 gdbserver、端口转发
符号表加载失败检查 -g 选项、sysroot 路径
断点不生效检查优化级别、源代码一致性

VSCode 相关

问题解决方案
launch.json 错误检查 JSON 格式、路径格式
无法连接检查 GDB Server、端口转发
变量显示异常检查符号表、优化级别

Coredump 相关

问题解决方案
文件未生成检查 ulimit、core_pattern
文件过大使用压缩、限制内存
分析失败检查可执行文件版本、符号表

调试技巧

  1. 使用日志:在关键位置添加日志输出,帮助定位问题
  2. 逐步缩小范围:先用简单方法(如打印)定位大致位置,再用 GDB 精确定位
  3. 保存现场:遇到崩溃时,及时保存 Coredump 文件
  4. 版本管理:保留带调试信息的可执行文件,便于后续分析
  5. 工具组合:ADB + GDB + VSCode 配合使用,提高调试效率