跳到主要内容

SDK 内核调试指南

本文档介绍如何使用 CKLink 调试器配合 GDB 对 V861 SDK 的 Linux 内核进行调试,包括硬件连接、软件环境配置、调试会话操作等内容。

概述

调试工具简介

V861 SDK 内核调试采用「CKLink + GDB」的调试方案,下表帮助您快速了解该方案的特点:

工具功能概述适用场景
CKLink平头哥 RISC-V 调试器,内置 GDB Server内核调试、U-Boot 调试、裸机程序调试
GDBGNU 调试器,支持断点、单步、变量查看命令行调试、脚本自动化
VSCode图形化调试环境(可选)大型项目调试、可视化操作

调试架构

┌─────────────────┐                    ┌─────────────────┐
│ PC Side │ │ Board Side │
│ │ │ │
│ ┌───────────┐ │ USB/Ethernet │ ┌───────────┐ │
│ │ GDB │◄─┼────────────────────┼──│ CKLink │ │
│ │ │ │ │ │ Server │ │
│ └───────────┘ │ │ └─────┬─────┘ │
│ │ │ │JTAG │
│ vmlinux │ │ ▼ │
│ Source Code │ │ ┌───────────┐ │
│ │ │ │ C907 │ │
│ │ │ │ (SoC) │ │
│ │ │ └───────────┘ │
└─────────────────┘ └─────────────────┘

CKLink 通过 JTAG 接口连接目标芯片,PC 端的 GDB 通过网络端口与 CKLink 内置的 GDB Server 通信,实现对目标芯片的调试。

硬件要求

项目要求
调试器CKLink 调试器(平头哥 T-Head 出品)
开发板V861-BGA_PER1 开发板(或其他 V861 系列开发板)
连接线JTAG 连接线(10Pin 或 20Pin)
PCWindows 或 Linux 系统

软件要求

软件说明
XuanTie Debug Server平头哥调试服务器软件(DebugServerConsole)
RISC-V GDBRISC-V 架构 GDB 调试器(SDK 工具链自带)
内核源码带调试信息的内核源码

CKLink 是平头哥(T-Head)推出的 RISC-V 调试器,专为调试 RISC-V 架构处理器设计。它具有以下特点:

  • 原生 RISC-V 支持:完整支持 RISC-V 调试规范
  • 内置 GDB Server:无需额外配置,直接与 GDB 对接
  • 多核调试支持:支持多核处理器的同步调试
  • 多种连接方式:支持 USB 和以太网连接
型号接口连接方式适用场景
CKLink LiteJTAG/SWDUSB个人开发、便携调试
CKLink ProJTAG/SWDUSB/以太网团队开发、远程调试

工作原理

CKLink 的核心是一个协议转换器,将 GDB 的调试命令转换为 JTAG 协议信号:

GDB Commands ──► GDB Server (CKLink) ──► JTAG Protocol ──► Target CPU


TCP/IP Port
(default: 2241)

硬件连接

JTAG 接口位置

V861-BGA_PER1 开发板的 JTAG 调试接口位于开发板正面,编号 26。全志平台也支持将 TF 卡口复用为 JTAG 功能,也可以用卡口作为调试口使用。

image-20260321160544276

TF 卡口 JTAG 复用功能示例

image-20260321160705711

接线说明

CKLink 与开发板 JTAG 接口的连接关系如下:

CKLink 信号JTAG 信号说明
TCKTCK时钟信号
TMSTMS测试模式选择
TDITDI测试数据输入
TDOTDO测试数据输出
GNDGND地线
VCCVCC目标板电源检测(可选)
RSTRST复位信号(可选)
警告
备注

注意事项

备注
  1. 连接前请确保开发板处于断电状态
  2. 确认 JTAG 接口线序正确,避免接反损坏芯片
  3. VCC 信号仅用于电平检测,不可用于供电

:::

连接示意与配置

在这里我们使用 JTAG 连接 PH 口或者连接 PF 口,

PH 口连接示意图

image-20260321160941636

PH 口配置方式

C907 JTAG 口

  • 配置 BOOT0 使一开始就切换到 PH 作为 C907 JTAG,配置 device/config/chips/{chip}/configs/{board}/sys_config.fex
[jtag_para]
jtag_enable = 1
jtag_ms = port:PH9<7><default><default><default>
jtag_ck = port:PH10<7><default><default><default>
jtag_do = port:PH11<7><default><default><default>
jtag_di = port:PH12<7><default><default><default>
  • 如果内核启动了有驱动切换了,需要强制切回来(这里为了方便将PH CFG2全切 mux7,也可以先读出来再把有需要的切到对应的 mux)
echo 0x02000154 0x77777777 > /sys/class/sunxi_dump/write

E907 JTAG 口

  • 配置 BOOT0 使一开始就切换到 PH 作为 E907 JTAG,配置 device/config/chips/{chip}/configs/{board}/sys_config.fex
[jtag_para]
jtag_enable = 1
jtag_ms = port:PH9<2><default><default><default>
jtag_ck = port:PH10<2><default><default><default>
jtag_do = port:PH11<2><default><default><default>
jtag_di = port:PH12<2><default><default><default>
  • 如果内核启动了有驱动切换了,需要强制切回来(这里为了方便将PH CFG2全切 mux2,也可以先读出来再把有需要的切到对应的 mux)
echo 0x02000154 0x22222222 > /sys/class/sunxi_dump/write

PF 连接示意图

image-20260321161004608

PF 口配置方式

C907 JTAG 口

  • 配置 BOOT0 使一开始就切换到 PF 作为 C907 JTAG,配置 device/config/chips/{chip}/configs/{board}/sys_config.fex
[jtag_para]
jtag_enable = 1
jtag_ms = port:PF0<6><default><default><default>
jtag_ck = port:PF1<6><default><default><default>
jtag_do = port:PF3<6><default><default><default>
jtag_di = port:PF5<6><default><default><default>
  • 如果内核启动了有驱动切换了,需要强制切回来(这里为了方便将PF全切 mux6,也可以先读出来再把有需要的切到对应的 mux)
echo 0x020000f0 0x66666666 > /sys/class/sunxi_dump/write

E907 JTAG 口

  • 配置 BOOT0 使一开始就切换到 PF 作为 E907 JTAG,配置 device/config/chips/{chip}/configs/{board}/sys_config.fex
[jtag_para]
jtag_enable = 1
jtag_ms = port:PF0<3><default><default><default>
jtag_ck = port:PF1<3><default><default><default>
jtag_do = port:PF3<3><default><default><default>
jtag_di = port:PF5<3><default><default><default>
  • 如果内核启动了有驱动切换了,需要强制切回来(这里为了方便将PF全切 mux3,也可以先读出来再把有需要的切到对应的 mux)
echo 0x020000f0 0x33333333 > /sys/class/sunxi_dump/write

软件环境配置

安装 XuanTie Debug Server

Linux 环境

(1)获取安装包

从玄铁官网下载安装包:玄铁官网下载

安装包中包含:

  • XuanTie-DebugServer-linux-i386-*.sh.tar.gz:32位系统
  • XuanTie-DebugServer-linux-x86_64-*.sh.tar.gz:64位系统

(2)安装步骤

# 解压安装包
tar -xzf XuanTie-DebugServer-linux-x86_64-*.sh.tar.gz

# 添加执行权限
chmod +x XuanTie-DebugServer-linux-*.sh

# 执行安装(需要 sudo 权限)
sudo ./XuanTie-DebugServer-linux-*.sh -i

(3)选择安装路径

安装过程会提示设置安装路径:

  • 默认路径:直接按回车,安装到 /usr/bin/
  • 自定义路径:输入绝对路径后确认

(4)验证安装

DebugServerConsole -v

Windows 环境

(1)获取安装包

从玄铁官网下载 XuanTie-DebugServer-windows*.zip

(2)安装步骤

  1. 解压 zip 文件
  2. 双击运行 Setup.exe
  3. 按向导完成安装(建议勾选 ICE Driver 和 Tutorial)

(3)运行程序

  • GUI 版:DebugServer.exe
  • Console 版:DebugServerConsole.exe

XuanTie Debug Server 运行参数

Console 版 Debug Server 通过启动参数配置运行时行为。常用参数如下:

参数说明默认值
-setclk iceclk设定 JTAG 时钟频率,默认单位 MHz,支持 kHz12
-port port设定 socket 通信端口2241
-arch tcsky/riscv/auto选择调试架构auto
-list-ice列出当前连接的 ICE 设备-
-select-ice serial_number指定 ICE 串号连接-
-prereset连接前执行 nreset 操作不执行
-v/-version查看版本号-
-h/--help查看帮助信息-
提示
备注

参数说明

备注
  • JTAG 时钟频率上限:CKLink-Pro/CKLink-V1 为 24MHz,CKLink-Lite 为 2500kHz
  • -arch auto 会自动探测调试架构(RISC-V DM 或 XuanTie HAD)

:::

安装 GDB 调试工具

V861 SDK 已自带 RISC-V GDB,位于工具链目录:

# 内核编译工具链
out/toolchain/Xuantie-900-gcc-linux-6.6.36-glibc-x86_64-V3.3.0-20260204/bin

内核编译配置

为了使内核支持调试,需要开启以下配置选项:

开启内核调试信息

make kernel_menuconfig

导航到以下路径并勾选:

Kernel hacking  --->
Compile-time checks and compiler options --->
[*] Debug information
[*] Rely on the toolchain's implicit default DWARF version
[*] Reduce debugging information (可选项,减小符号表大小)

image-20260321161600265

相关配置选项说明

配置项说明
CONFIG_DEBUG_INFO编译内核时生成调试信息
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT使用工具链提供的 DWARF 格式
CONFIG_DEBUG_INFO_REDUCED精简调试信息,减小内核体积

重新编译内核

# 编译内核
make -j8

# 生成的带调试信息的内核文件
# vmlinux: 带调试符号的内核映像
# System.map: 内核符号表

编译完成后,vmlinux 文件位于内核源码根目录,用于 GDB 加载符号表。


启动调试会话

启动 XuanTie Debug Server

查找 ICE 设备

连接 CKLink 到 PC 后,查看设备状态:

DebugServerConsole -list-ice

启动 Debug Server

# 使用默认参数启动(端口2241,频率12MHz)
DebugServerConsole

# 指定端口和频率
DebugServerConsole -port 2241 -setclk 12

# 指定 ICE 设备
DebugServerConsole -select-ice <serial_number>

启动成功后,Debug Server 会在指定端口监听 GDB 连接。

image-20260321164016614

连接 GDB

启动 GDB

进入工具链目录并启动 GDB:

# 进入工具链目录
cd out/toolchain/Xuantie-900-gcc-linux-6.6.36-glibc-x86_64-V3.3.0-20260204/bin

# 启动 GDB
./riscv64-unknown-linux-gnu-gdb

image-20260321162350439

连接 Debug Server

在 GDB 中连接 Debug Server:

(gdb) target remote localhost:2241

连接成功后,目标 CPU 会暂停运行,等待调试命令。

image-20260321164337560

加载内核符号

加载 vmlinux 符号表

(gdb) file /path/to/vmlinux

例如这里演示的

(gdb) file ../../../kernel/build/vmlinux

image-20260321164438485

验证符号加载

# 查看调用栈
(gdb) backtrace

image-20260321165008201


XuanTie Debug Server 命令行功能

Debug Server 提供命令行交互功能,支持在 GDB 连接前后进行调试操作。

寄存器操作

# 打印寄存器值
p $pc # 打印 PC 寄存器
p $sp # 打印 SP 寄存器
p $dmstatus # 打印 DM 状态寄存器
p target # 打印目标板信息

# 设置寄存器值
set $pc=0x20000
set $r0=0x10000000

内存操作

# 打印内存值(Word 大小)
p *0x10000000

# 设置内存值
set *0x10000000=0x1

其他命令

命令说明
singlestep / si单步执行
setclk 3修改 JTAG 频率为 3MHz
cacheflush刷新 L1 Cache
cacheflush l2 0x0 0x10000刷新 L2 Cache
p target打印目标信息
p cpu打印当前 CPU 编号(多核)
q / quit退出 Debug Server
help打印帮助信息

内核调试实战

设置断点

按函数名设置断点

(gdb) break start_kernel
Breakpoint 1 at 0xffffffc000123456: file kernel/printk/printk.c, line 1234.

image-20260321164825618

按文件和行号设置断点

(gdb) break linux-6.6-xuantie/init/main.c:1234

按条件设置断点

(gdb) break do_sys_open if flags & O_RDWR

查看和管理断点

# 查看所有断点
(gdb) info breakpoints

# 禁用断点
(gdb) disable 1

# 启用断点
(gdb) enable 1

# 删除断点
(gdb) delete 1

单步调试

继续执行

(gdb) continue

程序将继续执行,直到遇到断点或被手动中断。

单步执行

# 单步执行(不进入函数)
(gdb) next

# 单步执行(进入函数)
(gdb) step

# 执行到函数返回
(gdb) finish

# 执行到指定行
(gdb) until 100

查看变量与寄存器

查看变量值

# 打印变量
(gdb) print var_name

# 打印结构体
(gdb) print *struct_ptr

# 打印数组
(gdb) print array[0]@10

# 查看局部变量
(gdb) info locals

# 查看函数参数
(gdb) info args

查看寄存器

# 查看所有寄存器
(gdb) info registers

# 查看特定寄存器
(gdb) print $pc
(gdb) print $sp

查看调用栈

# 查看调用栈
(gdb) backtrace

# 切换栈帧
(gdb) frame 2

# 查看当前栈帧信息
(gdb) info frame

image-20260321164947944

调试内核模块

加载模块符号

# 获取模块加载地址
(gdb) info sharedlibrary

# 加载模块符号
(gdb) add-symbol-file /path/to/module.ko 0xffffffc000000000

高级调试技巧

调试启动过程

调试内核启动过程需要在内核启动早期设置断点。

调试 start_kernel

(gdb) break start_kernel
(gdb) continue

调试 U-Boot 跳转内核

在 U-Boot 阶段设置断点,跟踪内核启动流程。

调试设备驱动

设置驱动探测断点

# 在驱动 probe 函数设置断点
(gdb) break xxx_driver_probe
(gdb) continue

查看设备树信息

# 查看 of_device_id 匹配
(gdb) print *of_match_table

多核调试

V861 采用双核异构设计,支持多核调试。

查看多核状态

# 查看所有 CPU
(gdb) info threads

# 切换 CPU
(gdb) thread 2

image-20260321165101501

同步控制

# 暂停所有 CPU
(gdb) set scheduler-locking on

# 恢复所有 CPU
(gdb) set scheduler-locking off

常见问题排查

连接失败

ICE 设备无法识别

可能原因:

  1. USB 驱动未安装(Windows)
  2. USB 线缆损坏
  3. ICE 设备故障

解决方案:

  1. Windows 环境确保安装时勾选了 ICE Driver
  2. 更换 USB 线缆或接口
  3. Linux 环境检查 USB 设备:lsusb
  4. 使用 DebugServerConsole -list-ice 查看设备列表

无法连接目标芯片

可能原因:

  1. JTAG 接线错误
  2. 目标芯片未上电
  3. JTAG 频率过高
  4. JTAG 接口被禁用

解决方案:

  1. 检查 JTAG 连接线序
  2. 确认开发板已上电
  3. 降低 JTAG 频率:DebugServerConsole -setclk 1
  4. 检查芯片 JTAG 配置

ICE 固件升级提示

运行 Debug Server 时提示 ICE Upgrade:

解决方案:

  1. 选择"是"进行固件升级
  2. 升级完成后重新插拔 ICE
  3. 重新启动 Debug Server 连接

断点不生效

可能原因:

  1. 内核编译未开启调试信息
  2. 符号表与运行内核不匹配
  3. 代码被优化

解决方案:

  1. 检查 CONFIG_DEBUG_INFO 配置
  2. 确保使用正确的 vmlinux 文件
  3. 降低优化级别或使用 __attribute__((optimize("O0")))

符号表加载失败

可能原因:

  1. vmlinux 文件路径错误
  2. vmlinux 不包含调试信息
  3. GDB 版本不兼容

解决方案:

  1. 使用绝对路径加载 vmlinux
  2. 使用 file vmlinux 验证文件格式
  3. 检查 GDB 版本是否支持 DWARF4

附录

GDB 内核调试命令速查表

功能命令说明
连接控制
连接目标target remote localhost:2241连接 Debug Server
断开连接disconnect断开当前连接
断点操作
设置断点(函数)break func_name在函数入口设置断点
设置断点(行号)break file.c:100在指定行设置断点
设置条件断点break func if cond条件断点
查看断点info breakpoints显示所有断点
删除断点delete num删除指定断点
执行控制
继续执行continue继续运行
单步(不进入)next执行一行,不进入函数
单步(进入)step执行一行,进入函数
执行到返回finish执行到当前函数返回
变量查看
打印变量print var打印变量值
打印结构体print *ptr打印指针指向的结构体
查看局部变量info locals显示局部变量
查看寄存器info registers显示寄存器
调用栈
查看调用栈backtrace显示函数调用栈
切换栈帧frame num切换到指定栈帧
多核调试
查看线程info threads显示所有 CPU/线程
切换线程thread num切换到指定 CPU
锁定调度set scheduler-locking on锁定其他 CPU

相关参考资料