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

问题描述:

我遇到了GDB和内核空间中分配的一些缓冲区的问题。缓冲区由内核模块分配,内核模块应该分配连续的内存块,然后通过mmap()调用将内存映射到用户空间。然而,GDB似乎无法随时访问这些块。例如,创GDB断点后:GDB无法访问mmap()内核分配的内存?

(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中有效。

+0

因此,你的应用程序段错误,而它试图访问此映射*和* gdb说,它无法访问映射吗?难道由于某种原因映射变得无法访问,而/ proc/smaps只是不显示这个?这是哪个内核模块? – 2010-09-03 22:56:41

+0

是的,但GDB在segfault之前甚至无法访问映射,就我所知,它也无法在任何时候访问此内核模块的任何映射。我认为可能映射变得无法访问,但我对内核内存管理知之甚少,不知道可能是什么原因,以及为什么/ proc/smaps不能反映这种变化。分配这些模块的模块是德州仪器的连续存储器(CMEM)模块。它与CodecEngine API一起使用,用于管理目标为不具有MMU的协处理器的缓冲区。 – 2010-09-03 23:04:30

关于为什么gdb无法访问你想要的内存,我相信Linux不会通过ptrace()访问I/O内存。根据cmemk.c(我在linuxutils_2_25.tar.gz中找到),mmap()确实在所讨论的内存中设置了VM_IO标志。

要从gdb访问此内存,请在程序中添加一个读取此内存并使gdb调用此函数的函数。

+0

好的,我没有意识到这个限制,并且cmem确实设置了VM_IO(就像/ dev/mem的驱动程序一样,所以这很有意义)。谢谢。 任何想法为什么GDB会声明地址超出堆栈帧1的边界而不是堆栈帧2? – 2010-09-03 23:54:31

+0

这可能是你正在寻找的错误。 1. Wrapper()得到一个有效的指针2.另一个线程(或Wrapper(),不太可能)释放这个指针3. Wrapper()仍然将这个指针传递给Writer()4. Writer()将这个指针传递给fwrite() 5. fwrite()使用这个指针并死掉 – sigjuice 2010-09-04 00:19:56

+0

实际上,缓冲区地址是一个全红鲱鱼。原来另一个线程正在关闭文件指针,所以fwrite因此死亡。在线程拆卸后,缓冲区本身不会被释放,直到进程关闭。谢谢您的帮助! – 2010-09-04 02:43:48

请参阅examining-mmaped-addresses-using-gdb讨论在另一个线程中,尤其是答案here。您应该能够在模块的mmap实现中为您的VMA添加自定义vm_operations_struct

另请参阅Linux内核中的mm/memory.c。当get_user_pages()失败时,代码将尝试调用驱动程序中的自定义vma->vm_ops->access实现来访问内存。