GDB监视x86上的DMA控制器内存访问



我以QEMU/KVM来宾身份运行基于FreeBSD的内核。

我正在开发一个基于FreeBSD的操作系统内核SCSI驱动程序,遇到了read系统调用产生损坏数据的问题。

为了解决这个问题,我使用运行在QEMU中的内核,并希望跟踪DMA控制器执行的内存访问,DMA控制器负责将数据传递到用户提供的缓冲区。在QEMU的情况下,控制器是QEMU SCSI/ATA Disk设备。所以我试图在用户提供的缓冲区上设置一个观察点

示例:

int sys_read(struct thread *td, struct read_args *uap)上设置断点时,我从用户那里得到了一些缓冲区:

(gdb) p uap->buf
$5 = 0x7ffd4593f000 "User buffer initial data"
(gdb) watch *0x7ffd4593f000
Hardware watchpoint 7: *0x7ffd4593f000
(gdb) c

问题是观察点永远不会被击中。为什么?我想用它来理解从设备传输到内存的检查数据。

有可能从DMA控制器观看访问吗?

UPD:

我设法达到了警戒点。它看起来如下:

Thread 3 hit Hardware watchpoint 7: *0x7ffd4593f000                                                                                                                                                                
                                                                                                                                             
Old value = 1750343715                                                                                                                                                                                             
New value = 1819043144                                                                                                                                                                                             
0x00005586ec68f146 in ?? ()                                                                                                                                                                                        
(gdb) bt                                                                                                                                                                                                           
#0  0x00005586ec68f146 in ?? ()
#1  0x654b206f6c6c6548 in ?? ()
#2  0x6f7266206c656e72 in ?? ()
#3  0x707372657375206d in ?? ()
#4  0x6574617200656361 in ?? ()
#5  0x6d69562079622064 in ?? ()
#6  0x20230a2e312e3820 in ?? ()
#7  0x2079616d20756f59 in ?? ()
#8  0x2074692074696465 in ?? ()
#9  0x7227756f79206669 in ?? ()
...
#509 0x0a632e6e69616d2f in ?? ()
#510 0x32312c30352c347c in ?? ()
#511 0x323436312c37312c in ?? ()
#512 0x222c323037343132 in ?? ()
#513 0x0000000000000000 in ?? ()

它很可能是正确的,因为显示为旧值

新值但奇怪的是,在QEMU启动时,它只被点击一次。随后的read系统调用不会触发观察点。为了让它被击中,我重新启动QEMU并重新设置它。

这种堆叠竞赛可能意味着什么?

为QEMU的gdbstub提供的观察点处理实际上只用于客户CPU完成的访问,而不用于DMA从模拟设备完成的访问。我对它的出现感到惊讶,对这种行为有点奇怪也不感到惊讶。

如果您可以使用纯仿真(即不是KVM、hvf或whpx(在QEMU设置上重新编程,那么我的调试建议是在主机gdb中运行QEMU本身,并使用主机gdb在主机内存上设置一个与客户内存的相关位相对应的观察点。不幸的是,这需要一些QEMU内部的知识来找到主机内存,并通常理解正在发生的事情,并将QEMU正在做的事情与客户机执行的事情联系起来

补充调试提示:如果你可以在bug被触发之前拍摄一个"快照",这会给你一个更短的重现时间,即"快照";从快照加载并触发错误";而不是";引导整个客户操作系统和用户空间然后触发错误";。更多详细信息,请参阅此博客文章。

补充调试技巧2:如果你把";用主机gdb调试QEMU";方法,您可以使用反向调试器rr,这对于内存损坏错误非常方便,因为您可以说"现在向后执行到最后一次接触该存储器的任何东西";。更多信息请点击此帖子。

最新更新