2009-03-17 4 views
14

Я использую драйвер, который я разместил в Direct Memory Access in Linux, чтобы нанести некоторый физический ram в адрес пользовательского пространства. Однако я не могу использовать GDB для просмотра любого из адресов; то есть x 0x12345678 (где 0x12345678 - это возвращаемое значение mmap) с ошибкой «Не удается получить доступ к памяти по адресу 0x12345678».Рассмотрение mmaped адресов с использованием GDB

Есть ли способ сообщить GDB, что эта память может быть просмотрена? В качестве альтернативы, есть что-то другое, что я могу сделать в mmap (либо вызов, либо реализация foo_mmap там), который позволит ему получить доступ к этой памяти?

Обратите внимание, что я не спрашиваю об/DEV/MEM (как в первом фрагменте там), но о ттар в памяти, полученного через ioremap(), virt_to_phys() и remap_pfn_range()

+0

Кажется, это специфично для/dev/mem – jpalecek

+0

может быть, но я не использую/dev/mem;) – Mikeage

ответ

11

Я считаю, что 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' 
+0

Хорошая идея. Я надеялся избежать этого (основные дампы, одинаковое использование отладчика независимо от того, используется ли модуль (или даже если мы используем linux)), но это может быть единственным возможным вариантом. Если я не могу найти способ заставить ptrace работать, я приму это решение. – Mikeage

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; 
} 
+0

Нет, mmap удалось, и printf на следующей строке успешно читает переменную. – Mikeage

+0

Не могли бы вы предоставить текущие источники кода? – kyku

+0

См. Связанный вопрос; а не первый маленький фрагмент, но длинный модуль и короткое приложение для пользовательского пространства. Обратите внимание, что в модуле я добавил virt_to_phys (pt) >> PAGE_SHIFT, как это предложено в комментариях. – Mikeage

2

Это мое понимание того, что GDB будет использовать ptrace копаться в памяти процесса. Возможно, вам следует написать простую программу, которая просто придает вашему процессу и использует ptrace для чтения из этой памяти. Это может помочь уменьшить проблему, лежащую в основе. Если у вас нет проблем, значит, вы знаете, что я ошибаюсь :), или что-то еще нехорошее происходит с GDB.

+1

GDB действительно использует ptrace, а вызовы ptrace. Использование GDB по какой-то причине должно быть неудачным. Самый простой способ доказать, что это происходит, - запустить GDB под strace. Я уверен, что проблема в том, что драйвер ядра не реализует поддержку ptrace должным образом (или вообще). –

+0

, вероятно, нет; Я написал модуль ядра :) Что мне нужно сделать, чтобы убедиться, что ptrace работает? Вы можете увидеть источники в связанном вопросе. – Mikeage

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 
0

Если вы открываете гнездо AF_PACKET и mmap, gdb не может получить доступ к этой памяти. Таким образом, у вашего драйвера нет проблем. Это либо проблема с ptrace, либо с gdb.

10

У меня есть ответ на вашу загадку :) Я искал всюду в Интернете без большой помощи и, наконец, отлаживал ее сам.

Это сообщение было хорошей отправной точкой для меня. Я хотел чего-то добиться в аналогичных строках, я применил драйвер 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; 
} 
0

Чтобы получить доступ к mmapped памяти, GDB будет вызывать ptrace, который будет затем вызвать __access_remote_vm(), чтобы получить доступ к mmapped памяти. Если память сопоставляется с такими флагами, как VMIO | VM_PFNMAP (например, remap_pfn_range() устанавливает их), GDB будет обращаться к памяти, хотя способ доступа vm, определенный пользователями.

Вместо того, чтобы писать собственную реализацию для доступа(), ядро ​​уже содержит общую версию под названием 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; 
    .... .... 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^