Domanda

Sto usando il driver che ho pubblicato su Accesso diretto alla memoria in Linux per convertire un po 'di RAM fisica in un indirizzo spazio utente. Tuttavia, non posso usare GDB per guardare nessuno degli indirizzi; vale a dire, x 0x12345678 (dove 0x12345678 è il valore restituito di mmap) non riesce con un errore "Impossibile accedere alla memoria all'indirizzo 0x12345678".

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

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

È stato utile?

Soluzione

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

Altri suggerimenti

Ho la risposta al tuo enigma :) Ho cercato ovunque online senza molto aiuto e alla fine ho eseguito il debug da solo.

Questo post è stato un buon punto di partenza per me. Volevo ottenere qualcosa in linee simili, avevo implementato un driver char con MMAP per mappare la mia memoria gestita personalizzata a un processo di spazio utente. 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 il PA della memoria. Si scopre che è necessario implementare una funzione di accesso per questa memoria implementando .access del vm_operations_struct del VMA. Di seguito è riportato 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;
}

Sono consapevole che GDB utilizzerà ptrace per curiosare nella memoria del tuo processo. Forse dovresti scrivere un semplice programma che si attacca al tuo processo e usa ptrace per leggere da quella memoria. Questo potrebbe aiutare a restringere il problema. Se ciò non ha problemi, allora sai che mi sbaglio :) o che qualcosa di strano sta accadendo con GDB.

vai " file di informazioni "

(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 caso contrario, puoi utilizzare " mem " per configurare gli 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

Per accedere alla memoria mmapped, GDB chiamerà ptrace, che quindi chiamerà __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 attraverso il metodo di accesso di vm definito dagli utenti.

Invece di scrivere la nostra propria implementazione per access (), il kernel fornisce già una versione generica chiamata generic_access_phys (), e questo metodo potrebbe essere facilmente collegato tramite vm_operations_struct come faceva il 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;
    .... ....
}

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 l'applicazione fosse eseguita normalmente, si otterrebbe un errore di segmentazione. Inoltre, forse il tuo driver è rovinato e dovresti verificare che in realtà puoi accedere alla memoria dall'interno del 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;
}

Se apri un socket AF_PACKET e lo apri mmap, gdb non può accedere a questa memoria. Quindi non c'è nessun problema con il tuo driver. È un problema con ptrace o con gdb.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top