跳到主要内容

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

相关参考资料