GNU/Linux >> Linux Esercitazione >  >> Linux

Come eseguire il debug del kernel Linux con GDB e QEMU?

Proverei:

(gdb) target remote localhost:1234
(gdb) continue

Usando l'opzione '-s' qemu resta in ascolto sulla porta tcp::1234, alla quale puoi connetterti come localhost:1234 se sei sulla stessa macchina. L'opzione '-S' di Qemu fa sì che Qemu interrompa l'esecuzione finché non dai il comando continue.

La cosa migliore sarebbe probabilmente dare un'occhiata a un tutorial GDB decente per andare d'accordo con quello che stai facendo. Questo sembra piuttosto carino.


Procedura dettagliata testata sull'host Ubuntu 16.10

Per iniziare rapidamente da zero, ho creato un esempio minimo di QEMU + Buildroot completamente automatizzato su:https://github.com/cirosantilli/linux-kernel-module-cheat/blob/c7bbc6029af7f4fab0a23a380d1607df0b2a3701/gdb-step-debugging.md Major i passaggi sono descritti di seguito.

Per prima cosa prendi un filesystem root rootfs.cpio.gz . Se ne hai bisogno, considera:

  • un init minimo -solo immagine eseguibile:https://unix.stackexchange.com/questions/122717/custom-linux-distro-that-runs-just-one-program-nothing-else/238579#238579
  • un sistema interattivo Busybox:https://unix.stackexchange.com/questions/2692/what-is-the-smallest-possible-linux-implementation/203902#203902

Quindi sul kernel Linux:

git checkout v4.15
make mrproper
make x86_64_defconfig
cat <<EOF >.config-fragment
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_GDB_SCRIPTS=y
EOF
./scripts/kconfig/merge_config.sh .config .config-fragment
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage \
                   -initrd rootfs.cpio.gz -S -s \
                   -append nokaslr

Su un altro terminale, dall'interno dell'albero del kernel di Linux, supponendo di voler avviare il debug da start_kernel :

gdb \
    -ex "add-auto-load-safe-path $(pwd)" \
    -ex "file vmlinux" \
    -ex 'set arch i386:x86-64:intel' \
    -ex 'target remote localhost:1234' \
    -ex 'break start_kernel' \
    -ex 'continue' \
    -ex 'disconnect' \
    -ex 'set arch i386:x86-64' \
    -ex 'target remote localhost:1234'

e abbiamo finito!!

Per i moduli del kernel vedi:Come eseguire il debug dei moduli del kernel Linux con QEMU?

Per Ubuntu 14.04, GDB 7.7.1, hbreak era necessario, break i punti di interruzione del software sono stati ignorati. Non è più il caso in 16.10. Vedi anche:https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944

Il disordinato disconnect e ciò che viene dopo è per aggirare l'errore:

Remote 'g' packet reply is too long: 000000000000000017d11000008ef4810120008000000000fdfb8b07000000000d352828000000004040010000000000903fe081ffffffff883fe081ffffffff00000000000e0000ffffffffffe0ffffffffffff07ffffffffffffffff9fffff17d11000008ef4810000000000800000fffffffff8ffffffffff0000ffffffff2ddbf481ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000

Discussioni correlate:

  • https://sourceware.org/bugzilla/show_bug.cgi?id=13984 potrebbe essere un bug di GDB
  • La risposta del pacchetto 'g' remoto è troppo lunga
  • http://wiki.osdev.org/QEMU_and_GDB_in_long_mode osdev.org è come al solito una fantastica fonte per questi problemi
  • https://lists.nongnu.org/archive/html/qemu-discuss/2014-10/msg00069.html
  • nokaslr :https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb/421287#421287

Limitazioni note:

  • il kernel Linux non supporta (e non compila nemmeno senza patch) con -O0 :Come de-ottimizzare il kernel Linux e compilarlo con -O0?
  • GDB 7.11 ti lascerà a bocca aperta su alcuni tipi di completamento delle schede, anche dopo l'max-completions correzione:interruzione del completamento della scheda per file binari di grandi dimensioni Probabilmente un caso angolare che non era coperto in quella patch. Quindi un ulimit -Sv 500000 è un'azione saggia prima del debug. È esploso in particolare quando ho completato la scheda file<tab> per il filename argomento di sys_execve come in:https://stackoverflow.com/a/42290593/895245

Vedi anche:

  • https://github.com/torvalds/linux/blob/v4.9/Documentation/dev-tools/gdb-kernel-debugging.rst "documentazione" ufficiale del kernel Linux
  • Debug in tempo reale del kernel Linux, come viene eseguito e quali strumenti vengono utilizzati?

La risposta di BjoernID non ha funzionato davvero per me. Dopo la prima continuazione, non viene raggiunto alcun punto di interruzione e all'interruzione vedrei righe come:

0x0000000000000000 in ?? ()
(gdb) break rapl_pmu_init
Breakpoint 1 at 0xffffffff816631e7
(gdb) c
Continuing.
^CRemote 'g' packet reply is too long: 08793000000000002988d582000000002019[..]

Immagino che questo abbia qualcosa a che fare con diverse modalità della CPU (modalità reale nel BIOS rispetto alla modalità lunga quando Linux è stato avviato). Ad ogni modo, la soluzione è eseguire prima QEMU senza attendere (cioè senza -S ):

qemu-system-x86_64 -enable-kvm -kernel arch/x86/boot/bzImage -cpu SandyBridge -s

Nel mio caso, avevo bisogno di interrompere qualcosa durante l'avvio, quindi dopo alcuni decisicond, ho eseguito il comando gdb. Se hai più tempo (ad esempio devi eseguire il debug di un modulo che viene caricato manualmente), allora i tempi non contano davvero.

gdb consente di specificare i comandi che devono essere eseguiti all'avvio. Questo rende l'automazione un po' più facile. Per connettersi a QEMU (che ora dovrebbe essere già avviato), interrompere una funzione e continuare l'esecuzione, utilizzare:

gdb -ex 'target remote localhost:1234' -ex 'break rapl_pmu_init' -ex c ./vmlinux

Linux
  1. Controlla i comandi e le attività con il comando watch di Linux

  2. Analizza il kernel Linux con ftrace

  3. Come controllare la versione del sistema operativo e di Linux

  4. Come acquisire le sessioni del terminale e l'output con il comando di script Linux

  5. Debug del kernel Linux con QEMU

Come utilizzare il comando sleep di Linux con esempi

Come utilizzare il comando who in Linux con esempi

Come controllare la versione del kernel in Linux

Trova il nome della distribuzione Linux, la versione e i dettagli del kernel

Come trovare file con il comando fd in Linux

Come installare e proteggere Apache con HTTPS su Fedora Linux