SDK 内核调试指南
本文档介绍如何使用 CKLink 调试器配合 GDB 对 V861 SDK 的 Linux 内核进行调试,包括硬件连接、软件环境配置、调试会话操作等内容。
概述
调试工具简介
V861 SDK 内核调试采用「CKLink + GDB」的调试方案,下表帮助您快速了解该方案的特点:
| 工具 | 功能概述 | 适用场景 |
|---|---|---|
| CKLink | 平头哥 RISC-V 调试器,内置 GDB Server | 内核调试、U-Boot 调试、裸机程序调试 |
| GDB | GNU 调试器,支持断点、单步、变量查看 | 命令行调试、脚本自动化 |
| 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) |
| PC | Windows 或 Linux 系统 |
软件要求
| 软件 | 说明 |
|---|---|
| XuanTie Debug Server | 平头哥调试服务器软件(DebugServerConsole) |
| RISC-V GDB | RISC-V 架构 GDB 调试器(SDK 工具链自带) |
| 内核源码 | 带调试信息的内核源码 |
CKLink 调试器简介
什么是 CKLink?
CKLink 是平头哥(T-Head)推出的 RISC-V 调试器,专为调试 RISC-V 架构处理器设计。它具有以下特点:
- 原生 RISC-V 支持:完整支持 RISC-V 调试规范
- 内置 GDB Server:无需额外配置,直接与 GDB 对接
- 多核调试支持:支持多核处理器的同步调试
- 多种连接方式:支持 USB 和以太网连接
CKLink 型号与规格
| 型号 | 接口 | 连接方式 | 适用场景 |
|---|---|---|---|
| CKLink Lite | JTAG/SWD | USB | 个人开发、便携调试 |
| CKLink Pro | JTAG/SWD | USB/以太网 | 团队开发、远程调试 |
工作原理
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 功能,也可以用卡口作为调试口使用。

TF 卡口 JTAG 复用功能示例

接线说明
CKLink 与开发板 JTAG 接口的连接关系如下:
| CKLink 信号 | JTAG 信号 | 说明 |
|---|---|---|
| TCK | TCK | 时钟信号 |
| TMS | TMS | 测试模式选择 |
| TDI | TDI | 测试数据输入 |
| TDO | TDO | 测试数据输出 |
| GND | GND | 地线 |
| VCC | VCC | 目标板电源检测(可选) |
| RST | RST | 复位信号(可选) |
- 连接前请确保开发板处于断电状态
- 确认 JTAG 接口线序正确,避免接反损坏芯片
- VCC 信号仅用于电平检测,不可用于供电
连接示意与配置
在这里我们使用 JTAG 连接 PH 口或者连接 PF 口,
PH 口连接示意图

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 连接示意图

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)安装步骤
- 解压 zip 文件
- 双击运行
Setup.exe - 按向导完成安装(建议勾选 ICE Driver 和 Tutorial)
(3)运行程序
- GUI 版:
DebugServer.exe - Console 版:
DebugServerConsole.exe
XuanTie Debug Server 运行参数
Console 版 Debug Server 通过启动参数配置运行时行为。常用参数如下:
| 参数 | 说明 | 默认值 |
|---|---|---|
-setclk iceclk | 设定 JTAG 时钟频率,默认单位 MHz,支持 kHz | 12 |
-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 (可选项,减小符号表大小)

相关配置选项说明
| 配置项 | 说明 |
|---|---|
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 连接。

连接 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

连接 Debug Server
在 GDB 中连接 Debug Server:
(gdb) target remote localhost:2241
连接成功后,目标 CPU 会暂停运行,等待调试命令。

加载内核符号
加载 vmlinux 符号表
(gdb) file /path/to/vmlinux
例如这里演示的
(gdb) file ../../../kernel/build/vmlinux

验证符号加载
# 查看调用栈
(gdb) backtrace

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.
按文件和行号设置断点
(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

调试内核模块
加载模块符号
# 获取模块加载地址
(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

同步控制
# 暂停所有 CPU
(gdb) set scheduler-locking on
# 恢复所有 CPU
(gdb) set scheduler-locking off
常见问题排查
连接失败
ICE 设备无法识别
可能原因:
- USB 驱动未安装(Windows)
- USB 线缆损坏
- ICE 设备故障
解决方案:
- Windows 环境确保安装时勾选了 ICE Driver
- 更换 USB 线缆或接口
- Linux 环境检查 USB 设备:
lsusb - 使用
DebugServerConsole -list-ice查看设备列表
无法连接目标芯片
可能原因:
- JTAG 接线错误
- 目标芯片未上电
- JTAG 频率过高
- JTAG 接口被禁用
解决方案:
- 检查 JTAG 连接线序
- 确认开发板已上电
- 降低 JTAG 频率:
DebugServerConsole -setclk 1 - 检查芯片 JTAG 配置
ICE 固件升级提示
运行 Debug Server 时提示 ICE Upgrade:
解决方案:
- 选择"是"进行固件升级
- 升级完成后重新插拔 ICE
- 重新启动 Debug Server 连接
断点不生效
可能原因:
- 内核编译未开启调试信息
- 符号表与运行内核不匹配
- 代码被优化
解决方案:
- 检查
CONFIG_DEBUG_INFO配置 - 确保使用正确的 vmlinux 文件
- 降低优化级别或使用
__attribute__((optimize("O0")))
符号表加载失败
可能原因:
- vmlinux 文件路径错误
- vmlinux 不包含调试信息
- GDB 版本不兼容
解决方案:
- 使用绝对路径加载 vmlinux
- 使用
file vmlinux验证文件格式 - 检查 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 |