2009-03-17 12 views
14

Sto utilizzando il driver che ho inviato a Direct Memory Access in Linux in mmap un po 'di RAM fisica in un indirizzo di spazio utente. Tuttavia, non posso usare GDB per cercare alcun indirizzo; Ad esempio, x 0x12345678 (dove 0x12345678 è il valore restituito da mmap) non riesce con un errore "Impossibile accedere alla memoria all'indirizzo 0x12345678".Esaminare gli indirizzi mmaped utilizzando GDB

C'è un modo per dire a GDB che questa memoria può essere visualizzata? In alternativa, c'è qualcosa di diverso che posso fare in mmap (sia la chiamata o l'implementazione di foo_mmap lì) che gli consentirà di accedere a questa memoria?

Si noti che non sto chiedendo di/dev/mem (come nel primo frammento di lì), ma circa un mmap alla memoria acquisita tramite ioremap(), virt_to_phys() e remap_pfn_range()

+0

Sembra che questo sia specifico per/dev/mem – jpalecek

+0

potrebbe essere, ma non sto usando/dev/mem;) – Mikeage

risposta

11

Credo che Linux non renda accessibile la memoria I/O tramite ptrace(). Potresti scrivere una funzione che legge semplicemente l'indirizzo di mmap e fa in modo che gdb lo invochi. Ecco una versione leggermente modificata del tuo programma foo-user.c insieme con l'output di una sessione 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

Buona idea. Speravo di evitare questo (dump di core, uso identico del debugger indipendentemente dal fatto che il modulo sia usato o anche se stiamo usando linux), ma questa potrebbe essere l'unica opzione possibile. Se non riesco a trovare un modo per far funzionare ptrace, accetterò questa soluzione. – Mikeage

0

penso che se tale memoria non è accessibile da GDB, allora non viene mappata nello spazio degli indirizzi del processo e quindi si ottiene "Impossibile accedere alla memoria agli indirizzi 0x12345678". Se questa applicazione fosse eseguita normalmente, si otterrebbe un errore di segmentazione. Inoltre, forse il tuo driver è fregato e dovresti controllare che tu possa effettivamente accedere alla memoria dal kernel. Prova con l'esempio qui:

#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

No, il mmap è riuscito e un printf sulla riga successiva legge correttamente la variabile. – Mikeage

+0

Potresti fornire le fonti attuali del tuo codice? – kyku

+0

Vedere la domanda collegata; non il primo piccolo frammento, ma il modulo lungo e l'applicazione dello spazio utente breve. Si noti che nel modulo, ho aggiunto virt_to_phys (pt) >> PAGE_SHIFT come suggerito nei commenti. – Mikeage

2

E 'la mia comprensione che GDB userà ptrace a frugare nella memoria del processo. Forse dovresti scrivere un semplice programma che si collega semplicemente al tuo processo e usa ptrace per leggere da quella memoria. Ciò potrebbe aiutare a restringere quale sia il problema di fondo. Se questo non ha problemi, allora sai che ho torto :), o qualcos'altro che Fishy sta accadendo con GDB.

+1

GDB utilizza ptrace e le chiamate ptrace che gli usi GDB devono avere esito negativo per qualche motivo. Il modo più semplice per dimostrare che ciò che sta accadendo è eseguire GDB sotto strace. Sono abbastanza sicuro che il problema è che il driver del kernel non implementa il supporto di ptrace correttamente (o del tutto). –

+0

probabilmente no; Ho scritto il modulo del kernel :) Cosa devo fare per assicurarmi che ptrace funzioni? Puoi vedere le fonti nella domanda collegata. – Mikeage

1

si va "informazioni sul file"

(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 

In mancanza di questo, è possibile utilizzare "mem" per configurare intervalli di memoria.

(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

Se si apre un socket AF_PACKET e mmap, gdb non può accedere a questa memoria. Quindi non c'è un problema con il tuo autista. È un problema con ptrace o con gdb.

10

Ho la risposta al tuo enigma :) Ho cercato ovunque online senza molto aiuto e alla fine ho effettuato il debug di me stesso.

Questo post è stato un buon punto di partenza per me. Volevo ottenere qualcosa con linee simili, avevo implementato un driver di char con MMAP per mappare la mia memoria gestita personalizzata in un processo userspace. Quando si utilizza GDB, ptrace PEEK chiama access_process_vm() per accedere a qualsiasi memoria nel VMA. Ciò causa un errore EIO poiché l'accesso generico non può ottenere l'AP della memoria. Si scopre che devi implementare una funzione di accesso per questa memoria implementando l'accesso di vm_operations_struct del tuo VMA. Sotto è un esempio:

//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

Per accedere alla memoria mmapped, GDB chiamerà ptrace, che sarà quindi chiamare __access_remote_vm() per accedere alla memoria mmapped. Se la memoria è mappata con flag come VMIO | VM_PFNMAP (ad esempio, remap_pfn_range() li imposta), GDB accederà alla memoria tramite il metodo di accesso di vm definito dagli utenti.

Invece di scrivere la nostra implementazione per l'accesso(), kernel fornisce già una versione generica chiamata generic_access_phys(), e questo metodo potrebbe essere facilmente collegato via vm_operations_struct come dispositivo/dev/mem ha fatto:

static const struct vm_operations_struct mmap_mem_ops = { 
     .access = generic_access_phys }; 

int mmap_mem() 
{ 
    .... .... 
    vma->vm_ops = &mmap_mem_ops; 
    .... .... 
} 
Problemi correlati