AMD GPU的断点指令

    很多人都知道x86 CPU的断点指令,即著名的INT 3,机器码为0xCC。在Nvidia的GPU中,比如著名的伏特微架构,也有一条断点指令,叫BPT,是Breakpoint的缩写。

    那么,在AMD GPU中是否也有这样一条指令呢?

    在回答这个问题前,先看一段AMD GPU的指令吧。

s_addc_u32    s17, s17, s19               // 000000000168: 82111311
     s_lshr_b64    s[16:17], s[16:17], 16        // 00000000016C: 8F909010
     s_mul_i32     s5, s5, s13                // 000000000170: 92050D05
     s_add_u32     s5, s5, s16                // 000000000174: 80051005
     s_mul_i32     s4, s4, s8                // 000000000178: 92040804
     v_add_u32     v3, vcc, s4, v0             // 00000000017C: 32060004
=>   s_nop         0x0000                  // 000000000180: BF800000
     s_load_dword  s4, s[6:7], 0x18             // 000000000184: C0020103 00000018
     s_nop         0x0000                  // 00000000018C: BF800000
     s_load_dword  s5, s[6:7], 0x40             // 000000000190: C0020143 00000040
     s_nop         0x0000                 // 000000000198: BF800000
     s_load_dword  s12, s[6:7], 0x20           // 00000000019C: C0020303 00000020
     s_nop         0x0000                 // 0000000001A4: BF800000
     s_load_dword  s13, s[6:7], 0x48            // 0000000001A8: C0020343 00000048
     s_waitcnt     lgkmcnt(0)                // 0000000001B0: BF8C007F
     s_nop         0x0000                // 0000000001B4: BF800000
     v_add_u32     v9, vcc, s4, v3             // 0000000001B8: 32120604
     s_nop         0x0000                  // 0000000001BC: BF800000
     v_add_u32     v13, vcc, s5, v3       // 0000000001C0: 321A0605
     v_mov_b32     v5, s8                // 0000000001C4: 7E0A0208

    AMD的GPGPU已经发展了几轮,比较著名的有Terascale微架构,发展了三代后,被GCN(Graphics Core Next)微架构所取代,GCN已经发展了6代,预计2020年退役。

    上面这段汇编代码就是GCN微架构的指令。

    GCN的指令是从Terascale的VLIW指令演变而来的。VLIW的字面意思就是“非常长的指令字”。不过GCN的指令已经不再是VLIW风格。不仅指令的长度不是那么长了(32或者64位),更重要的是每条指令的操作都是针对当前算核的单一数据项,操作比较单纯,不再强调指令级别的并行。

    上面清单右侧注释部分就是指令的机器码。可以看到大多数是32位,个别是64位。

    GCN指令有一个非常大的特色,那就是把所有操作分为标量和向量两个大类。上面s_开头的都是标量指令,v_开头的都是向量指令。在GPU内部,标量指令会送给标量ALU(sALU)来执行,向量指令会送给向量ALU执行(vALU)。AMD GPU也有与Nvidia的WARP相同的概念,叫wavefront。每个wavefront是64个线程。考虑到在每个算核(kernel)的开头结尾,以及某些逻辑部分常常只需要一个处理器执行,比如对于上面的那么多条s_指令,就只要一个sALU执行就可以了,不需要浪费vALU,因为vALU一行动,就是64个一排碾压过去。这样考虑,AMD的设计是非常聪明的。

    再回头来说断点指令。浏览GCN的指令集,没有专门的断点指令。但这并代表真的没有。因为没有这样的基本功能,顶层的调试功能怎么工作的啊。在AMD的工具链中,无论是CodeXL还是ROCm-GDB都是支持断点功能的。

    那么是哪条指令呢?我觉得是S_TRAP。这是可以在GPU程序中触发陷阱的指令,与x86的INT n指令如出一辙。

    GCN定义了十几种指令编码格式,S_TRAP属于SOPP类型,其编码格式如下图所示。

2169d062faa94c3cdf7b8f5b15e9c7f3.png

可见,S_TRAP指令的长度是一个DWORD(32位),低16位为立即数,用来指示陷阱号(TRAP_ID)。因为高位部分是固定的,所以S_TRAP指令的机器码总是0xBF92xxxx这样的编码。

    迷信一点说,我第一次看到S_TRAP指令就觉得亲切,觉得它可以用来实现断点功能。但是调试器中是否真的使用这个指令设置断点,还是另有妙方呢?

    这个周末在写作《软件调试》中的相关内容。虽然凭经验和直觉,觉得上面的推测把握很大。但是没有官方文档描述,也没有源代码证实,把推测的结论写进书里让我很不安。

    怎么办呢?无奈之时,突然灵光一现。可以上IDA啊。IDA是著名的反汇编工具。引起名称与著名的程序员之母Ada Lovelace相似,所以其图标是就是Ada。

28afd6b88778e6b5a39ffdfcb79372a8.png

    几年前曾经购买过正版的IDA,但是光盘和注册码不知在何处了。只好临时到官网下载一个免费版本。

   安装很顺利,启动IDA,美丽的图标一闪,就到主界面了。打开AMD官方调试SDK中的核心调试模块(DBE)。然后找到用来设置软件断点的API——HwDbgCreateCodeBreakpoint。

    HwDbgCreateCodeBreakpoint内部经过几次调用,最终执行实际断点设置和恢复的是下面这个方法:

    bool HwDbgBreakpoint::Set(HwDbgBreakpoint *const this, bool enable)

    在这个函数内部,看到多处0xBFxxxxxx这样的“身影”:

cmp     eax, 0BF800000h

cmp     eax, 0BF920000h

    上面一个是S_NOP指令的机器码,后一个就是S_TRAP。特别地,下面这几条指令让我如释重负:

.text: 002017A8                 mov     edx, 0BF920007h

.text: 002017AD                 mov     rax, [rdi]

.text: 002017B0                 call    qword ptr [rax+18h]

    其中的0BF920007h是触发TRAP_ID为7的陷阱,结合另一处看到的常量定义:

    var TRAP_ID_DEBUGGER         = 0x07

    于是,可以确定无疑,官方调试SDK中设置代码断点的方法就是使用S_TRAP指令,更确切地说,是S_TRAP 0x7。这与INT 3何其相似。

    感谢IDA,感谢Ada!

93ac995896d0e12d49d2f1db8a4ba8cd.png

AI时代,我们一起学习GPU。希望深入学习GPU的格友,欢迎垂询第二期GPU研习班

***********************************************************

正心诚意,格物致知,以人文情怀审视软件,以软件技术改变人生。

欢迎关注格友公众号

ef9debdb9e37cef2523ef3f5fa1c2562.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值