DOCA 文档 v2.10.0

DOCA DPA GDB 服务器工具

本文档介绍了 DPA GDB 服务器工具。

信息

DPA GDB 服务器工具目前处于 Beta 测试阶段。

DPA GDB 服务器工具 (dpa-gdbserver) 能够调试 FlexIO DEV 程序。

用于调试的 DEV 程序使用 FlexIO 进程所有者提供的令牌(8 字节值)进行选择。

信息

任何熟悉 RISC-V 架构的 GDB 均可用于调试。有关如何使用 GDB 的信息,请参阅页面。

术语表

术语

描述

PUD

被调试进程。用于调试的 DEV 端进程。

EU

执行单元(类似于硬件 CPU 核心)

DPA

数据路径加速器

RPC

远程进程通信。FlexIO 中用于立即运行 DEV 端代码的机制。运行时限制为 6 秒。

HOST

管理 dev 端代码(即 DEV)的 x86 或 aarch64 Linux 操作系统

DEV

RISC-V 代码,由 HOST 加载到 DPA 的设备中。由不同类型的中断触发运行。DEV 端直接连接到 ConnectX 适配器卡。

GDB

GNU 项目调试器。允许用户在程序执行时对其进行监控。

GDBSERVER

用于远程调试程序的工具

RTOS

在 RISC-V 核心上运行的实时操作系统。管理中断处理和对 DEV 用户进程例程的调用。

RSP

远程串行协议。用于 GDB 和 GDBSERVER 之间的交互。


已知限制

  • DPA GDB 技术不会捕获致命错误。因此,如果发生致命错误,则应使用 core dump(由 flexio_coredump_create() 创建)。

  • DPA GDB 技术不支持 Outbox 访问。GDB 用户无法写入 Doorbell 或 Window 配置区域。

  • DPA GDB 技术不支持 Window 访问。对 Window 内存的读/写操作无法正常工作。

令牌

被调试进程 (PUD) 可以公开调试令牌。每个使用此令牌的外部进程都可以完全访问具有给定令牌的进程。为了不 постоянно 显示它(例如,出于安全原因),用户可以临时修改其主机应用程序。请参阅 flexio_process_udbg_token_get()

应用程序启动时连接

如果需要调试的代码在启动后立即开始运行,则用户应修改主机应用程序以在启动时停止,以便用户有时间运行 dpa-gdbserver。一种可能的方法是在进程创建后立即放置函数 getchar()

虚拟线程概念

DPA 调试需要考虑的是,PUD 并非始终都有正在运行的线程(例如,进程的线程可能存在,但正在等待传入的数据包)。在常规 Linux 应用程序中,这种情况是不可能的,GDB 也不支持这种情况。

因此,当没有线程运行时,dpa-gdbserver 会报告一个虚拟线程

gdb

复制
已复制!
            

(gdb) info thread   Id   Target Id                                Frame * 1    Thread 1.805378433 (Dummy Flexio thread) 0x0800000000000000 in ?? () (gdb)

在这种情况下,用户可以检查内存、创建断点并给出 continue 命令。

对于虚拟线程,无法执行 stepnextstepi 等命令。

看门狗问题

RTOS 具有看门狗定时器,它将 DEV 代码中断进程限制为 120 秒。当用户使用 GDB 连接到 DEV 时,此定时器会停止。因此,用户在调试时将没有时间限制。

默认情况下,dpa-gdbserver 使用 TCP 端口 1981 并在 EU 29 上运行。如果这与其他应用程序冲突(或者如果其他 dpa-gdbserver 实例正在运行),用户应按如下方式更改默认设置

Bash

复制
已复制!
            

$> dpa-gdbserver mlx5_0 -T <token> -s <port> -E <eu_id>

调试准备

如果需要,修改您的 FlexIO 应用程序。确保 HOST 代码打印 udbg_token 并在需要时等待 GDB 连接

C 代码。主机端。diff

复制
已复制!
            

+ uint64_t udbg_token;   flexio_process_create(..., &flexio_process);   + udbg_token = flexio_process_udbg_token_get(flexio_process); + if (udbg_token) + printf("Process created. Use token >>> %#lx <<< for debug\n", udbg_token);   + printf("Stop point for waiting of GDB connection. Press Enter to continue..."); /* Usually you don't need this stop point */ + fflush(stdout); + getchar();

从 FlexIO 应用程序中提取 DPA 应用程序。例如

Bash

复制
已复制!
            

$> dpacc-extract cc-host/app/host/flexio_app_name -o flexio_app_name.rv5


开始调试

  1. 运行您的 FlexIO 应用程序。它应公开调试令牌

    Bash

    复制
    已复制!
                

    $> flexio_app_name mlx5_0 Process created. Use token >>> 0xd6278388ce4e682c <<< for debug

  2. 使用收到的调试令牌运行 dpa-gdbserver

    Bash

    复制
    已复制!
                

    $> dpa-gdbserver mlx5_0 -T 0xd6278388ce4e682c Registered on device mlx5_0 Listening for GDB connection on port 1981

  3. 运行任何支持 RISC-V 的 GDB。例如,gdb-multiarch

    Bash

    复制
    已复制!
                

    $> gdb-multiarch -q flexio_app_name.rv5 Reading symbols from flexio_app_name.rv5... (gdb)

  4. 如果需要,使用正确的 TCP 端口和主机名连接到 gdbserver

    gdb

    复制
    已复制!
                

    (gdb) target remote :1981 Remote debugging using :1981 0x0800000000000000 in ?? ()

DPA 特定调试技术

从虚拟线程过渡到真实线程的简单示例

在虚拟线程和真实线程之间切换不是 GDB 下调试的标准做法。在理想情况下,用户应确切知道其所有例程的入口点,并可以为所有例程设置断点。然后,用户可以运行 continue 命令

gdb

复制
已复制!
            

(gdb) target remote :1981 Remote debugging using :1981 0x0800000000000000 in ?? () (gdb) info threads Id Target Id Frame * 1 Thread 1.805378433 (Dummy Flexio thread) 0x0800000000000000 in ?? () (gdb) b foo Breakpoint 1 at 0x400000b2: file ../tests/path/hello.c, line 58. (gdb) b bar Breakpoint 2 at 0x40000518: file ../tests/path/hallo.c, line 113. (gdb) continue Continuing.

为您的 DEV 程序启动中断(取决于您的任务),GDB 应捕获断点,现在 PUD 的真实线程应代替虚拟线程出现

gdb

复制
已复制!
            

(gdb) continue Continuing. (gdb) [New Thread 1.2] [New Thread 1.130] [New Thread 1.258] [New Thread 1.386] [Switching to Thread 1.2]   Thread 2 hit Breakpoint 1, foo(thread_arg=9008) at ../tests/path/hello.c:58 58 struct host_data *hdata = NULL; (gdb) info threads Id Target Id Frame * 2 Thread 1.2 (Process 0 thread 0x1 GVMI 0) foo (arg=9008) at ../tests/path/hello.c:58 3 Thread 1.130 (Process 0 thread 0x81 GVMI 0) foo (arg=9264) at ../tests/path/hello.c:58 4 Thread 1.258 (Process 0 thread 0x101 GVMI 0) foo (arg=9648) at ../tests/path/hello.c:58 5 Thread 1.386 (Process 0 thread 0x181 GVMI 0) foo (arg=9904) at ../tests/path/hello.c:58 (gdb)

从此时起,您可以像往常一样检查内存和跟踪代码。

从虚拟线程过渡到真实线程的复杂示例

在更复杂的情况下,中断发生在 GDB 连接之后。在这种情况下,真实线程应开始运行,但由于 PUD 处于 HALT 状态而无法运行。用户可以键入命令 info threads,看到新线程代替旧的虚拟线程,然后手动切换到新线程

gdb

复制
已复制!
            

(gdb) target remote :1981 Remote debugging using :1981 0x0800000000000000 in ?? () (gdb) info threads Id Target Id Frame * 1 Thread 1.805378433 (Dummy Flexio thread) 0x0800000000000000 in ?? () (gdb) info threads [New Thread 1.32769] Id Target Id Frame 2 Thread 1.32769 (Process 0 thread 0x8000 GVMI 0) bar (arg=0xc0, len=0) at /path/lib/src/stub.c:167   The current thread <Thread ID 1> has terminated. See `help thread'. (gdb) thread 2 [Switching to thread 2 (Thread 1.32769)] #0 bar (arg=0xc0, len=0) at /path/lib/src/stub.c:167 167 { (gdb) bt #0 bar (arg=0xc0, len=0) at /path/lib/src/stub.c:167 #1 0x000000004000017a in foo (thread_arg=3221) at ../path/dev/hello.c:182 #2 0x0000000000000000 in ?? () Backtrace stopped: frame did not save the PC (gdb)

注意

第 4 行和第 7 行中的相同命令 info threads 给出不同的结果。发生这种情况是因为中断发生在实例之间,并且真实代码开始运行。

用户必须手动切换到新线程(请参阅第 14 行)。之后,他们可以像往常一样跟踪/调试流程(即,使用命令 stepnextstepi)。

在不完成 PUD 的情况下完成真实线程

每个中断处理程序在某个时候都会完成其路径,并将 CPU 资源返回给 RTOS。最常见的方法是调用函数 flexio_dev_thread_reschedule()。对此函数执行 next 命令将具有与 continue 命令相同的效果

gdb

复制
已复制!
            

205 __dpa_thread_fence(__DPA_MEMORY, __DPA_W, __DPA_W); (gdb) next 206 flexio_dev_cq_arm(dtctx, app_ctx.rq_cq_ctx.cq_idx, app_ctx.rq_cq_ctx.cq_number); (gdb) next 208 if ((dev_errno = flexio_dev_get_and_rst_errno(dtctx))) { (gdb) next 213 print_sim_str("Nothing to do. Wait for next duar\n", 0); (gdb) next 214 flexio_dev_thread_reschedule(); (gdb) next

信息

GDB 将一直等待,直到用户键入 ^C 或在下一次中断发生后到达断点。

信息

DPA GDB 服务器工具已通过 gdb-multiarch(版本 9.2)和 RISC-V 工具链中的 GDB 版本 12.1 验证。

注意

GDB 服务器应支持 GDB RSP(远程串行协议)中针对 GDB 桩描述的所有命令。但仅支持最常见的 GDB 命令。

如果 dpa-gdbserver 发生错误,请提供以下数据

  • 使用的 GDB(名称和版本)

  • 重现问题的命令序列

  • DPA GDB 服务器工具控制台输出

  • DPA GDB 服务器工具日志目录内容(有关详细信息,请参阅下一部分)

  • 可选 - 以详细模式运行 dpa-gdbserver 时打印的输出数据

工具日志目录

对于每次运行,都会创建一个临时目录,模板为 /tmp/flexio_gdbs.XXXXXX

要找到最新的目录,请运行以下命令

Bash

复制
已复制!
            

$> ls -ldtr /tmp/flexio_gdbs.* | tail


gdbserver 的详细程度

默认情况下,dpa-gdbserver 不会将任何日志信息打印到屏幕。向命令行添加 - v 选项会增加详细程度,从而将其他信息打印到 dpa-gdbserver 终端显示屏。详细程度根据命令行开关中“v”的数量递增(即 -vv-vvv 等)。

一个 -v 显示 RSP 交换。这是一个文本协议,因此用户可以读取和理解来自 GDB 的请求以及来自 GDB 服务器的响应

gdbserver.log -v

复制
已复制!
            

<<<<< "qTStatus" >>>>> "" <<<<< "?" >>>>> "S05" <<<<< "qfThreadInfo" >>>>> "mp01.30011981" <<<<< "qsThreadInfo" >>>>> "l" <<<<< "qAttached:1" >>>>> "1" <<<<< "Hc-1" >>>>> "OK" <<<<< "qC" >>>>> "QCp01.30011981"

信息

在示例中,<<<<<>>>>> 分别用于指示从 GDB 接收和传输到 GDB 的数据。

当以更高的详细程度运行时(例如,使用选项 -vv 或更高版本运行 dpa-gdbserver),将显示与 RTOS 模块的交换

gdbserver.log -vv

复制
已复制!
            

<<<<< "qfThreadInfo" / 2/dgdbs_handler - cmd 0x5 / 2/dgdbs_handler - retval 0x4 >>>>> "mp01.30011981" <<<<< "qsThreadInfo" / 2/dgdbs_handler - cmd 0x5 / 2/dgdbs_handler - retval 0x5 >>>>> "l" <<<<< "m800000000000000,4" / 2/dgdbs_handler - cmd 0xc / 2/dgdbs_handler - retval 0x9 >>>>> "E0a" <<<<< "m7fffffffffffffc,4" / 2/dgdbs_handler - cmd 0xc / 2/dgdbs_handler - retval 0x9 >>>>> "E0a" <<<<< "qSymbol::" >>>>> "OK"

信息

/ #/ 开头的行提供从 DEV 端打印的内部 RTOS 线程数。


本节提供有关命令和方法的有用信息,这些命令和方法可以在用户执行 DPA 调试时提供帮助。这与 dpa-gdbserver 本身无关。但这与远程调试和 FlexIO 源代码有关。

命令 "directory"

GDB 可以在与完成编译的主机不同的主机上运行。例如,用户可能已在 host1 上编译并运行其应用程序,并在 host2 上运行其 GDB 实例。在这种情况下,用户将看到错误消息 ../xxx/yyy/zzz/your_file.c: No such file or directory。要解决此问题,请将源代码复制到运行 GDB 的主机(示例中的 host2)。确保保存原始代码层次结构。使用 GDB 命令 directory 通知 GDB 源代码的位置

host2 上的 gdb

复制
已复制!
            

host2~$> gdb-multiarch -q /tmp/my_riscv.elf Reading symbols from /tmp/my_riscv.elf... (gdb) b foo Breakpoint 1 at 0x4000016c: file ../xxx/yyy/zzz/my_file.c, line 182. (gdb) target remote host1:1981 Remote debugging using host1:1981 0x0800000000000000 in ?? () (gdb) c Continuing. [New Thread 1.32769] [Switching to Thread 1.32769]   Thread 2 hit Breakpoint 1, foo (thread_arg=5728) at ../xxx/yyy/zzz/my_file.c:182 182 ../xxx/yyy/zzz/my_file.c: No such file or directory. (gdb) directory /tmp/apps/ Source directories searched: /tmp/apps:$cdir:$cwd (gdb) list 179 struct flexio_dev_thread_ctx *dtctx; 180 uint64_t dev_errno; 181 182 print_sim_str("=====> NET event handler started\n", 0); 183 184 flexio_dev_print("Hello GDB user\n"); 185

注意

注意 GDB 报告的确切路径。命令 directory 的参数应指向此路径的起点。例如,如果 GDB 查找 ../xxx/yyy/zzz,并且您将源代码放置在本地目录 /tmp/copy_of_worktree 中,则命令应为 (gdb) directory /tmp/copy_of_worktree/xxx/,而不是 (gdb) directory /tmp/copy_of_worktree/

有时,*.elf 文件提供来自根目录的全局路径。在这种情况下,请使用命令 set substitute-path <from> <to>。例如,如果文件 /foo/bar/baz.c 已移动到 /mnt/cross/baz.c,则命令 (gdb) set substitute-path /foo/bar /mnt/cross 指示 GDB/foo/bar 替换为 /mnt/cross,这允许 GDB 找到文件 baz.c,即使该文件已被移动。

有关指定源目录的更多示例,请参阅 GDB 文档的页面。

Core Dump 用法

如果代码即使在项目的宿主机端正确实现的情况下仍遇到致命错误,则会保存 core dump,从而可以分析 core。它应准确指向发生致命错误的位置。命令 backtrace 可用于检查内存及其寄存器。更改帧以查看回溯列表中每个函数的局部变量

gdb

复制
已复制!
            

$> gdb-multiarch -q -c crash_demo.558184.core /tmp/my_riscv.elf Reading symbols from /tmp/my_riscv.elf...   [New LWP 1] #0 0x000000004000126e in read_test (line=153, ptr=0x30) at /xxx/yyy/zzz/my_file.c:109 109 val = *(volatile uint64_t *)ptr; (gdb) bt #0 0x000000004000126e in read_test (line=153, ptr=0x30) at /xxx/yyy/zzz/my_file.c:109 #1 0x000000004000031a in tlb_miss_test (op_code=1) at /xxx/yyy/zzz/my_file.c:153 #2 0x0000000040000144 in test_thread_err_events_entry_point (h2d_daddr=3221258560) at /xxx/yyy/zzz/my_file.c:588 #3 0x00000000400013fc in _dpacc_flexio_dev_arg_unpack_test_err_events_dev_test_thread_err_events_entry_point (argbuf=0xc0008228, func=0x400000b0 <test_thread_err_events_entry_point>) at /tmp/dpacc_xExkvE/test_err_events_dev.dpa.device.c:67 #4 0x0000000040001680 in flexio_hw_rpc (host_arg=3221258752) at /local_home/www/flexio-sdk/libflexio-dev/src/flexio_dev_entry_point.c:75 #5 0x0000000000000000 in ?? () Backtrace stopped: frame did not save the PC (gdb) frame 4 #4 0x0000000040001680 in flexio_hw_rpc (host_arg=3221258752) at /local_home/igorle/flexio-sdk/libflexio-dev/src/flexio_dev_entry_point.c:75 75 retval = unpack_cb(&data_from_host->func_params.arg_buf, (gdb) p /x *data_from_host $2 = {poll_lkey = 0x1ff2b1, window_id = 0x3, poll_haddr = 0x55dc0f40b900, entry_point = 0x400013d8, func_params = {func_wo_pack = 0x0, dev_func_entry = 0x400000b0, arg_buf = 0xc0008140}} (gdb)


优化代码的调试

通常,编译和运行的是高度优化的代码。

可以考虑两种类型的代码错误

  • 逻辑错误

  • 与优化相关的错误

逻辑错误(例如,使用 & 而不是 &&)在代码的非优化版本中重现。与优化相关的错误(例如,忘记 volatile 分类、不使用内存屏障)仅影响优化。非优化代码更易于使用 GDB 进行跟踪,因为每个 C 指令都直接转换为汇编代码。

检查问题是否可以在非优化代码上重现是一种良好的实践。这有助于观察应用程序流程

Bash

复制
已复制!
            

$> build.sh -O 0

对于跟踪此代码,使用 GDB 命令 nextstep 应该足够了。

但是,如果问题只能在优化代码上重现,则应开始调试它。这将需要读取反汇编代码并使用 GDB 命令 stepi,因为要准确理解执行了哪个 C 代码行变得具有挑战性。

高级 RISC-V 命令的反汇编

DPA 核心在具有扩展指令集的 RISC-V CPU 上运行。GDB 可能不熟悉其中一些指令。因此,asm 视图模式显示数字而不是反汇编。在这种情况下,建议手动反汇编您的 RISC-V 二进制代码。将 dpa-objdump 实用程序与附加选项 --mcpu=nv-dpa-bf3一起使用。

bash

复制
已复制!
            

$> dpa-objdump -sSdxl --mcpu=nv-dpa-bf3 my_riscv.elf > my_riscv.asm

以下屏幕截图显示了差异

image-2024-1-25_12-27-13-version-1-modificationdate-1734555555593-api-v2.png

© 版权所有 2025 NVIDIA 公司。 上次更新时间:2025 年 2 月 12 日。