我正在使用我在Direct Memory Access in Linux发布的驱动程序将一些物理ram映射到用户空间地址。但是,我无法使用GDB来查看任何地址;即,x 0x12345678(其中0x12345678是mmap的返回值)失败,并显示错误“无法访问地址0x12345678处的内存”。
有没有办法告诉GDB可以查看这个内存?或者,我在mmap中可以做些什么(在foo_mmap的调用或实现),它将允许它访问这个内存?
请注意,我不是在询问/ dev / mem(如第一个代码片段),而是关于通过ioremap(),virt_to_phys()和remap_pfn_range()
获取的内存的mmap答案 0 :(得分:12)
我认为Linux不会通过ptrace()访问I / O内存。您可以编写一个只读取mmap的地址并让gdb调用它的函数。这是foo-user.c程序的略微修改版本以及gdb会话的输出。
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
char *mptr;
char peek(int offset)
{
return mptr[offset];
}
int main(void)
{
int fd;
fd = open("/dev/foo", O_RDWR | O_SYNC);
if (fd == -1) {
printf("open error...\n");
return 1;
}
mptr = mmap(0, 1 * 1024 * 1024, PROT_READ | PROT_WRITE,
MAP_FILE | MAP_SHARED, fd, 4096);
printf("On start, mptr points to 0x%lX.\n", (unsigned long) mptr);
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr,
*mptr);
mptr[0] = 'a';
mptr[1] = 'b';
printf("mptr points to 0x%lX. *mptr = 0x%X\n", (unsigned long) mptr,
*mptr);
close(fd);
return 0;
}
$ make foo-user CFLAGS=-g
$ gdb -q foo-user
(gdb) break 27
Breakpoint 1 at 0x804855f: file foo-user.c, line 27.
(gdb) run
Starting program: /home/me/foo/foo-user
On start, mptr points to 0xB7E1E000.
mptr points to 0xB7E1E000. *mptr = 0x61
Breakpoint 1, main () at foo-user.c:27
27 mptr[0] = 'a';
(gdb) n
28 mptr[1] = 'b';
(gdb) print peek(0)
$1 = 97 'a'
(gdb) print peek(1)
$2 = 98 'b'
答案 1 :(得分:10)
我对你的难题有了答案:)我在网上到处搜索没有太多帮助,最后自己调试了。
这篇文章对我来说是一个很好的起点。我想用类似的方式实现一些东西,我用MMAP实现了一个char驱动程序,将我的自定义托管内存映射到用户空间进程。使用GDB时,ptrace PEEK调用access_process_vm()来访问VMA中的任何内存。这会导致EIO错误,因为通用访问无法获取内存的PA。事实证明,您必须通过实现VMA的vm_operations_struct的.access来实现此内存的访问功能。以下是一个例子:
//Below code needs to be implemented by your driver:
static struct vm_operations_struct custom_vm_ops = {
.access = custom_vma_access,
};
static inline int custom_vma_access(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
return custom_generic_access_phys(vma, addr, buf, len, write);
}
static int custom_generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
void *buf, int len, int write)
{
void __iomem *maddr;
//int offset = (addr & (PAGE_SIZE-1)) - vma->vm_start;
int offset = (addr) - vma->vm_start;
maddr = phys_to_virt(__pa(custom_mem_VA));
if (write)
memcpy_toio(maddr + offset, buf, len);
else
memcpy_fromio(buf, maddr + offset, len);
return len;
}
答案 2 :(得分:2)
据我了解,GDB将使用ptrace在你的进程内存中徘徊。也许您应该编写一个简单的程序,它只是附加到您的进程并使用ptrace
从该内存中读取。这可能有助于缩小潜在问题的范围。如果这没有问题,那么你知道我错了:),或者GDB正在发生其他问题。
答案 3 :(得分:1)
你去“信息文件”
(gdb) help info files
Names of targets and files being debugged.
Shows the entire stack of targets currently in use (including the exec-file,
core-file, and process, if any), as well as the symbol file name.
(gdb) info files
Symbols from "/bin/ls".
Unix child process:
Using the running image of child Thread 4160418656 (LWP 10729).
While running this, GDB does not access memory from...
Local exec file:
`/bin/ls', file type elf32-powerpc.
Entry point: 0x10002a10
0x10000134 - 0x10000141 is .interp
0x10000144 - 0x10000164 is .note.ABI-tag
0x10000164 - 0x100008f8 is .gnu.hash
0x100008f8 - 0x10001728 is .dynsym
0x10001728 - 0x100021f3 is .dynstr
0x100021f4 - 0x100023ba is .gnu.version
...
0x0ffa8300 - 0x0ffad8c0 is .text in /lib/libacl.so.1
0x0ffad8c0 - 0x0ffad8f8 is .fini in /lib/libacl.so.1
0x0ffad8f8 - 0x0ffadbac is .rodata in /lib/libacl.so.1
0x0ffadbac - 0x0ffadd58 is .eh_frame_hdr in /lib/libacl.so.1
0x0ffadd58 - 0x0ffae4d8 is .eh_frame in /lib/libacl.so.1
0x0ffbe4d8 - 0x0ffbe4e0 is .ctors in /lib/libacl.so.1
0x0ffbe4e0 - 0x0ffbe4e8 is .dtors in /lib/libacl.so.1
...
(gdb) info sh
From To Syms Read Shared Object Library
0xf7fcf960 0xf7fe81a0 Yes /lib/ld.so.1
0x0ffd0820 0x0ffd5d10 Yes /lib/librt.so.1
0x0ffa8300 0x0ffad8c0 Yes /lib/libacl.so.1
0x0ff6a840 0x0ff7f4f0 Yes /lib/libselinux.so.1
0x0fdfe920 0x0ff1ae70 Yes /lib/libc.so.6
0x0fda23d0 0x0fdb0db0 Yes /lib/libpthread.so.0
如果失败,您可以使用“mem”配置内存范围。
(gdb) mem 1 1414
(gdb) info mem
Num Enb Low Addr High Addr Attrs
1 y 0x00000001 0x00000586 rw nocache
(gdb) disable mem 1
(gdb) info mem
Num Enb Low Addr High Addr Attrs
1 n 0x00000001 0x00000586 rw nocache
答案 4 :(得分:1)
要访问mmapped内存,GDB将调用ptrace,然后调用__access_remote_vm()来访问mmapped内存。如果使用诸如VMIO |之类的标志映射内存VM_PFNMAP(例如,remap_pfn_range()设置它们),GDB将通过用户定义的vm访问方法访问内存。
而不是编写我们自己的access()实现,内核已经提供了一个名为generic_access_phys()的通用版本,这个方法可以通过vm_operations_struct轻松链接,就像/ dev / mem设备那样:
static const struct vm_operations_struct mmap_mem_ops = {
.access = generic_access_phys };
int mmap_mem()
{
.... ....
vma->vm_ops = &mmap_mem_ops;
.... ....
}
答案 5 :(得分:0)
我认为如果GDB无法访问该内存,则它不会映射到您的进程地址空间,因此您将“无法访问地址为0x12345678的内存”。如果该应用程序正常运行,您将收到分段错误。此外,也许您的驱动程序被搞砸了,您应该检查您实际上是否可以从内核中访问内存。试试这里的例子:
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main() {
int fd = open("/dev/zero", O_RDONLY);
void* addr = mmap(NULL, 1024, PROT_READ, MAP_PRIVATE, fd, 0);
for (int x = 0; x < 10; x++) {
printf("%X\n", ((char*)addr)[x]);
}
close(fd);
return 0;
}
答案 6 :(得分:0)
如果打开AF_PACKET套接字并对其进行mmap,则gdb无法访问此内存。所以你的驱动程序没有问题。这是ptrace或gdb的问题。