2009-03-17 10 views
14

Estoy usando el controlador que publiqué en Direct Memory Access in Linux para asignar mmap a un ram físico en una dirección de espacio de usuario. Sin embargo, no puedo usar GDB para mirar ninguna de las direcciones; es decir, x 0x12345678 (donde 0x12345678 es el valor de retorno de mmap) falla con un error "No se puede acceder a la memoria en la dirección 0x12345678".Examinando las direcciones mmaped utilizando GDB

¿Hay alguna manera de decirle a GDB que se puede ver esta memoria? Alternativamente, ¿hay algo diferente que pueda hacer en mmap (ya sea la llamada o la implementación de foo_mmap allí) que le permita acceder a esta memoria?

Tenga en cuenta que yo no estoy preguntando por/dev/mem (como en el primer fragmento de allí), sino de una MMAP a la memoria adquirida a través de ioremap(), virt_to_phys() y() remap_pfn_range

+0

parece que esta es específico a/dev/mem – jpalecek

+0

podría ser, pero no lo estoy usando/dev/mem;) – Mikeage

Respuesta

11

Creo que Linux no hace que la memoria de E/S sea accesible a través de ptrace(). Puede escribir una función que simplemente lea la dirección mmap y haga que gdb lo invoque. Aquí hay una versión ligeramente modificada de su programa foo-user.c junto con el resultado de una sesión de 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

Buena idea. Esperaba evitar esto (volcados del núcleo, uso idéntico del depurador, se use o no el módulo (o incluso si usamos linux)), pero esta podría ser la única opción posible. Si no puedo encontrar una manera de hacer que ptrace funcione, aceptaré esta solución. – Mikeage

0

creo que si esa memoria no es accesible por GDB, entonces no se asigna a su espacio de direcciones de proceso y entonces obtiene "No se puede acceder a la memoria en las direcciones 0x12345678". Si esa aplicación se ejecutara normalmente, obtendría un error de segmentación. Además, tal vez su destornillador esté atornillado y debería verificar que realmente pueda acceder a la memoria desde dentro del kernel. Pruebe con el ejemplo aquí:

#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, el MMAP tuvieron éxito, y una printf en la línea siguiente lee con éxito la variable. – Mikeage

+0

¿Podría proporcionar las fuentes actuales de su código? – kyku

+0

Ver la pregunta vinculada; no es el primer pequeño fragmento, sino el módulo largo y la aplicación de espacio de usuario corto. Tenga en cuenta que en el módulo, he añadido virt_to_phys (pt) >> PAGE_SHIFT como se sugiere en los comentarios. – Mikeage

2

Es mi entendimiento de que el BGF va a utilizar ptrace a hurgar en la memoria de su proceso. Tal vez deba escribir un programa simple que simplemente se una a su proceso y use ptrace para leer de esa memoria. Esto podría ayudar a reducir el problema subyacente. Si eso no tiene problemas, entonces sabrá que estoy equivocado :), u otra cosa sospechosa está sucediendo con GDB.

+1

GDB utiliza ptrace, y las llamadas de seguimiento. Los usos de GDB deben estar fallando por algún motivo. La forma más sencilla de probar que eso es lo que está sucediendo es ejecutar GDB bajo esfuerzo. Estoy bastante seguro de que el problema es que el controlador del núcleo no implementa soporte ptrace correctamente (o en absoluto). –

+0

probablemente no; Escribí el módulo kernel :) ¿Qué debo hacer para asegurarme de que ptrace funcione? Puede ver las fuentes en la pregunta vinculada. – Mikeage

1

ir "Información de archivo"

(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 

en su defecto, puede utilizar "mem" para configurar los rangos de 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

Si abre un socket AF_PACKET y lo mapea, gdb no puede acceder a esta memoria. Entonces no hay un problema con su controlador. Es un problema con ptrace o con gdb.

10

Tengo la respuesta a su enigma :) He buscado en todas partes en línea sin mucha ayuda y finalmente lo depuré yo mismo.

Esta publicación fue un buen punto de partida para mí. Quería lograr algo en líneas similares, había implementado un controlador de char con MMAP para asignar mi memoria administrada personalizada a un proceso de espacio de usuario. Cuando usa GDB, ptrace PEEK llama a access_process_vm() para acceder a cualquier memoria en su VMA. Esto causa un error EIO ya que el acceso genérico no puede obtener el PA de su memoria. Resulta que debe implementar una función de acceso para esta memoria al implementar .access de vm_operations_struct de su VMA. A continuación se muestra un ejemplo:

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

Para acceder a la memoria mmapped, el BGF llamará ptrace, que a su vez llamar __access_remote_vm() para acceder a la memoria mmapped. Si la memoria está mapeada con indicadores como VMIO | VM_PFNMAP (por ejemplo, remap_pfn_range() los establece), GDB accederá a la memoria a través del método de acceso de vm definido por los usuarios.

En lugar de escribir nuestra propia aplicación para el acceso(), de almendra ya ofrece una versión genérica llamada generic_access_phys(), y este método podrían vincularse fácilmente a través de vm_operations_struct como lo hizo el dispositivo/dev/mem:

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

int mmap_mem() 
{ 
    .... .... 
    vma->vm_ops = &mmap_mem_ops; 
    .... .... 
} 
Cuestiones relacionadas