Изучение mmaped адресов с использованием GDB
Я использую драйвер, который я разместил в Прямой доступ к памяти в Linux, чтобы превратить некоторый физический ram в адрес пользовательского пространства. Однако я не могу использовать GDB для просмотра любого из адресов; то есть x 0x12345678 (где 0x12345678 - это возвращаемое значение mmap) с ошибкой "Невозможно получить доступ к памяти по адресу 0x12345678".
Есть ли способ сообщить GDB, что эта память может быть просмотрена? В качестве альтернативы, есть что-то другое, что я могу сделать в mmap (либо вызов, либо реализация foo_mmap там), который позволит ему получить доступ к этой памяти?
Обратите внимание, что я не спрашиваю о /dev/mem (как в первом фрагменте), а о mmap для памяти, полученной через ioremap(), virt_to_phys() и remap_pfn_range()
Ответы
Ответ 1
Я полагаю, что Linux не делает доступную память ввода/вывода через ptrace(). Вы можете написать функцию, которая просто считывает адрес 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'
Ответ 2
У меня есть ответ на вашу загадку:) Я искал всюду в Интернете без большой помощи и, наконец, сам отлаживал ее.
Этот пост был хорошей отправной точкой для меня. Я хотел чего-то добиться в подобных строках, я применил драйвер char с MMAP для сопоставления моей настраиваемой управляемой памяти с процессом пользовательского пространства. При использовании GDB ptrace PEEK вызывает access_process_vm() для доступа к любой памяти вашего VMA. Это вызывает ошибку EIO, поскольку общий доступ не может получить ПА вашей памяти. Оказывается, вам нужно реализовать функцию доступа для этой памяти, реализуя .access вашего VMA vm_operations_struct. Ниже приведен пример:
//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;
}
Ответ 3
Насколько я понимаю, GDB будет использовать ptrace для того, чтобы сориентироваться в вашей памяти процессов. Возможно, вам следует написать простую программу, которая просто подключается к вашему процессу и использует ptrace
для чтения из этой памяти. Это может помочь уменьшить проблему, лежащую в основе. Если у вас нет проблем, то вы знаете, что я ошибаюсь:), или что-то еще неприятное происходит с GDB.
Ответ 4
вы идете "информационные файлы"
(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
Ответ 5
Я думаю, что если эта память недоступна 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
Если вы откроете сокет AF_PACKET и mmap, gdb не сможет получить доступ к этой памяти. Таким образом, у вашего драйвера нет проблем. Это либо проблема с ptrace, либо с gdb.
Ответ 7
Чтобы получить доступ к mmapped памяти, GDB вызовет ptrace, который затем вызовет __access_remote_vm() для доступа к mmapped памяти. Если память сопоставляется с такими флагами, как VMIO | VM_PFNMAP (например, remap_pfn_range() устанавливает их), GDB будет обращаться к способу доступа к памяти, определенному пользователями.
Вместо того, чтобы писать собственную реализацию для доступа(), ядро уже предоставляет общую версию 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;
.... ....
}