GDB无法访问mmap()分配的内核内存?

10

我在使用GDB时遇到了一个问题,与内核空间中分配的一些缓冲区有关。这些缓冲区是由一个内核模块分配的,该模块应该分配连续的内存块,然后通过mmap()调用映射到用户空间。然而,GDB似乎无法在任何时候访问这些块。例如,在GDB中触发断点后:

(gdb) x /10xb 0x4567e000
0x4567e000:     Cannot access memory at address 0x4567e000

然而,在/proc//smaps中查看应用程序当前映射的内存区域,显示:
4567e000-456d3000 rwxs 8913f000 00:0d 883        /dev/cmem
Size:                340 kB
Rss:                 340 kB
Pss:                   0 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:            0 kB
Swap:                  0 kB

我之所以要研究这个问题,是因为在运行过程中,这个缓冲区地址(或类似方式分配的其他地址)会导致 SIGSEGV 错误。

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x49aea490 (LWP 652)]
0x402e4ea8 in fwrite () from /lib/libc.so.6
(gdb)
(gdb)
(gdb) where
#0  0x402e4ea8 in fwrite () from /lib/libc.so.6
#1  0x000eb394 in EncryptedWriter::Write (this=0x198600, buffRaw=0x4567e000 <Address     0x4567e000 out of bounds>, iLenRaw=719) at encrypted_writer.cpp:397
#2  0x0006b0f4 in EncryptionWrapper::Write (this=0x3ab2698, buffer=0x4567e000, size=719) at encryption.cpp:54

尽管缓冲区在崩溃之前被大量使用,/proc//smaps文件仍显示该缓冲区如上所述被映射,但仍会发生段错误。
我完全不知道为什么会发生这种情况,以及为什么映射在/proc中似乎是有效的,但在GDB中却从未出现。

你的应用程序在尝试访问这个映射时出现了段错误,而gdb也表示无法访问该映射?可能是由于某种原因导致该映射不可访问,而/proc/smaps没有显示出来?这是哪个内核模块? - Uli Schlachter
是的,但是GDB甚至在段错误之前也无法访问映射,据我所知,它也无法在任何时候访问此内核模块中的任何映射。我认为可能会出现映射变得不可访问的情况,但我对内核内存管理不够熟悉,不知道可能的原因以及为什么/proc/smaps不会反映这种变化。分配这些块的模块是来自德州仪器的连续内存(CMEM)模块。它与他们的CodecEngine API一起使用,用于管理缓冲区,这些缓冲区将被发送到没有MMU的协处理器。 - Ryan Talbot
2个回答

12
关于gdb无法访问您想要的内存的原因,我认为Linux不会通过ptrace()使I/O内存可访问。
根据我在linuxutils_2_25.tar.gz中找到的cmemk.c文件,mmap()确实在相关内存上设置了VM_IO标志。
要从gdb访问此内存,请向程序添加一个读取该内存的函数,并让gdb调用此函数。

啊,好的,我之前不知道这个限制,而且cmem确实设置了VM_IO(/dev/mem驱动程序也是如此,所以这很合理)。谢谢。你有没有想过为什么GDB在堆栈帧1中声明地址越界,但在堆栈帧2中却没有? - Ryan Talbot
这可能是你正在寻找的错误。1. Wrapper()获得一个有效指针2.另一个线程(或Wrapper(),可能性较小)释放此指针3. Wrapper()仍将此指针传递给Writer()4. Writer()将此指针传递给fwrite()5. fwrite()使用此指针并死机。 - sigjuice
实际上,缓冲区地址完全是一个误导。原来另一个线程正在关闭文件指针,所以fwrite因此而死亡。缓冲区本身直到进程关闭后才会释放,这发生在线程拆除之后。感谢你的帮助! - Ryan Talbot

2
请参考另一个讨论线程中的examining-mmaped-addresses-using-gdb,特别是这里的答案。在模块的mmap实现中,您应该能够向VMA添加自定义vm_operations_struct
此外,请参见Linux内核中的mm/memory.c。当get_user_pages()失败时,代码将尝试调用驱动程序中自定义的vma->vm_ops->access实现来访问内存。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接