web-dev-qa-db-de.com

Wie debugge ich den Linux-Kernel mit GDB und QEMU?

Ich bin neu in der Kernel-Entwicklung und würde gerne wissen, wie man den Linux-Kernel mit QEMU und gdb ausführt/debuggt. Ich lese gerade das Buch von Robert Love, aber leider hilft es dem Leser nicht, wie man die richtigen Tools installiert, um den Kernel auszuführen oder zu debuggen. Was ich also getan habe, war, diesem Tutorial http: //opensourceforu.efytimes zu folgen .com/2011/02/Kernel-Entwicklung-Debugging-using-Eclipse/ . Ich benutze Eclipse als IDE, um auf dem Kernel zu entwickeln, aber ich wollte, dass es zuerst unter QEMU/gdb funktioniert. Was ich bisher gemacht habe, war:

1) So kompilieren Sie den Kernel mit:

make defconfig (then setting the CONFIG_DEBUG_INFO=y in the .config)
make -j4

2) Sobald die Kompilierung abgeschlossen ist, starte ich Qemu mit:

qemu-system-x86_64 -s -S /dev/zero -kernel /Arch/x86/boot/bzImage

welche den Kernel im "gestoppten" Zustand starten

3) Also muss ich gdb benutzen, ich versuche folgenden Befehl:

gdb ./vmlinux

die laufen aber richtig ... Nun weiß ich nicht, was ich tun soll ... Ich weiß, dass ich Remote-Debugging für den Port 1234 (Standardport von Qemu) verwenden muss, wobei vmlinux als Symboltabellendatei verwendet wird Debuggen.

Meine Frage ist also: Was soll ich tun, um den Kernel auf Qemu auszuführen, meinen Debugger daran anzubinden und sie so zusammenzuarbeiten, damit sie mir das Leben mit der Kernel-Entwicklung erleichtern.

28
E-Kami

Ich würde versuchen:

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

Mit der Option '-s' kann qemu Port tcp :: 1234 abhören, zu dem Sie sich als localhost verbinden können: 1234, wenn Sie sich auf demselben Rechner befinden. Mit der Option "-S" von Qemu wird die Ausführung von Qemu angehalten, bis Sie den Befehl continue ausführen.

Das Beste wäre wahrscheinlich, sich ein anständiges GDB-Tutorial anzuschauen, um mit dem, was Sie tun, zurechtzukommen. Das hier sieht ganz nett aus.

24
BjoernD

Schritt für Schritt auf Ubuntu 16.10 Host getestet

Um ganz von vorne anzufangen, habe ich ein minimal automatisiertes QEMU + Buildroot-Beispiel erstellt: https://github.com/cirosantilli/linux-kernel-module-cheat/blob/c7bbc6029af7f403a3a380d1607df0b2a3701/gdb-step-debuging. md Wichtige Schritte werden unten beschrieben.

Holen Sie sich zuerst ein Root-Dateisystem rootfs.cpio.gz. Wenn Sie eine benötigen, sollten Sie Folgendes in Betracht ziehen:

Dann zum Linux-Kernel:

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

An einem anderen Terminal innerhalb des Linux-Kernel-Baums, nehmen Sie an, Sie möchten mit start_kernel das Debugging starten:

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'

und wir sind fertig !!

Für Kernel-Module siehe: Wie debugge ich Linux-Kernel-Module mit QEMU?

Für Ubuntu 14.04, GDB 7.7.1, hbreak wurde benötigt, wurden break Software-Haltepunkte ignoriert. In 16.10 nicht mehr der Fall. Siehe auch: https://bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944

Die chaotisch disconnect und was danach kommt, sollen den Fehler umgehen:

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

Verwandte Themen:

Bekannte Einschränkungen:

Siehe auch:

Die Antwort von BjoernID hat für mich nicht wirklich funktioniert. Nach der ersten Fortsetzung ist kein Haltepunkt erreicht und bei Interrupt würde ich folgende Zeilen sehen:

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

Ich denke, das hat etwas mit verschiedenen CPU-Modi zu tun (Real-Modus im BIOS vs. Long-Modus, wenn Linux gestartet ist). Die Lösung ist jedoch, QEMU zuerst auszuführen, ohne zu warten (d. H. Ohne -S):

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

In meinem Fall musste ich beim Booten etwas kaputt machen, so dass ich nach einigen Sekunden den Befehl gdb ausführte. Wenn Sie mehr Zeit haben (z. B. müssen Sie ein manuell geladenes Modul debuggen), spielt das Timing keine Rolle.

Mit gdb können Sie Befehle angeben, die beim Start ausgeführt werden sollen. Dies macht die Automatisierung etwas einfacher. Um eine Verbindung zu QEMU herzustellen (die jetzt bereits gestartet sein sollte), brechen Sie eine Funktion ab und setzen Sie die Ausführung fort:

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

Wenn Sie versuchen, vmlinux exe mit gdb zu starten, müssen Sie als erstes auf gdb cmds eingeben:

(gdb) Ziel-Remote-Localhost: 1234

(gdb) break start_kernel

(fortsetzen)

Dadurch wird der Kernel bei start_kernel zerstört.

2
Ritesh

Für mich ist die beste Lösung für das Debuggen des Kernels die Verwendung von gdb aus der Eclipse-Umgebung. Sie sollten nur den entsprechenden Port für gdb festlegen (muss derselbe sein, den Sie in der qemu-Startzeichenfolge angegeben haben) im Remote-Debugging-Abschnitt. Hier ist das Handbuch: http://www.sw-at.com/blog/2011/02/11/linux-kernel-development-and-debugging-using-Eclipse-cdt/

1
Alex Hoppus

Auf Linux-Systemen ist vmlinux eine statisch verknüpfte ausführbare Datei, die den Linux-Kernel in einem der von Linux unterstützten Objektdateiformate enthält, einschließlich ELF, COFF und a.out. Die vmlinux-Datei wird möglicherweise für das Kernel-Debugging, die Generierung von Symboltabellen oder andere Vorgänge benötigt, muss jedoch durch Hinzufügen eines Multiboot-Headers, eines Bootsektors und von Setup-Routinen bootfähig gemacht werden, bevor sie als Betriebssystemkernel verwendet werden kann.

Ein Image dieses ursprünglichen Root-Dateisystems muss an einem Ort gespeichert werden, auf den der Linux-Bootloader für die Boot-Firmware des Computers zugreifen kann. Dies kann das Root-Dateisystem selbst, ein Boot-Image auf einem optischen Datenträger, eine kleine Partition auf einem lokalen Datenträger (eine Boot-Partition, die normalerweise ext4- oder FAT-Dateisysteme verwendet) oder ein TFTP-Server (auf Systemen, die über Ethernet booten können) sein ).

  1. Kompilieren Sie den Linux-Kernel

    Erstellen Sie den Kernel mit dieser angewendeten Serie und aktivieren Sie CONFIG_DEBUG_INFO (lassen Sie jedoch CONFIG_DEBUG_INFO_REDUCED deaktiviert).

  2. Installieren Sie GDB und Qemu

    Sudo pacman -S gdb qemu
    
  3. Erstellen Sie initramfs

    #!/bin/bash
    
    # Os     : Arch Linux
    # Kernel : 5.0.3
    
    INIT_DIR=$(pwd)
    BBOX_URL="https://busybox.net/downloads/busybox-1.30.1.tar.bz2"
    BBOX_FILENAME=$(basename ${BBOX_URL})
    BBOX_DIRNAME=$(basename ${BBOX_FILENAME} ".tar.bz2")
    RAM_FILENAME="${INIT_DIR}/initramfs.cpio.gz"
    
    function download_busybox {
        wget -c ${BBOX_URL} 2>/dev/null
    }
    
    function compile_busybox {
        tar xvf ${BBOX_FILENAME} && cd "${INIT_DIR}/${BBOX_DIRNAME}/"
        echo "[*] Settings > Build options > Build static binary (no shared libs)"
        echo "[!] Please enter to continue"
        read tmpvar
        make menuconfig && make -j2 && make install
    }
    
    function config_busybox {
        cd "${INIT_DIR}/${BBOX_DIRNAME}/"
        rm -rf initramfs/ && cp -rf _install/ initramfs/
        rm -f initramfs/linuxrc
        mkdir -p initramfs/{dev,proc,sys}
        Sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} initramfs/dev/
    
    cat > "${INIT_DIR}/${BBOX_DIRNAME}/initramfs/init" << EOF
    #!/bin/busybox sh
    mount -t proc none /proc
    mount -t sysfs none /sys
    
    exec /sbin/init
    EOF
    
        chmod a+x initramfs/init
        cd "${INIT_DIR}/${BBOX_DIRNAME}/initramfs/"
        find . -print0 | cpio --null -ov --format=newc | gzip -9 > "${RAM_FILENAME}"
        echo "[*] output: ${RAM_FILENAME}"
    
    }
    
    download_busybox
    compile_busybox
    config_busybox
    
  4. Booten Sie den Linux-Kernel mit Qemu

    #!/bin/bash
    
    KER_FILENAME="/home/debug/Projects/kernelbuild/linux-5.0.3/Arch/x86/boot/bzImage"
    RAM_FILENAME="/home/debug/Projects/kerneldebug/initramfs.cpio.gz"
    
    qemu-system-x86_64 -s -kernel "${KER_FILENAME}" -initrd "${RAM_FILENAME}" -nographic -append "console=ttyS0"
    
    $ ./qemuboot_vmlinux.sh
    SeaBIOS (version 1.12.0-20181126_142135-anatol)
    
    
    iPXE (http://ipxe.org) 00:03.0 C980 PCI2.10 PnP PMM+07F92120+07EF2120 C980
    
    
    Booting from ROM...
    Probing EDD (edd=off to disable)... o
    [    0.019814] Spectre V2 : Spectre mitigation: LFENCE not serializing, switching to generic retpoline
    can't run '/etc/init.d/rcS': No such file or directory
    
    Please press Enter to activate this console.
    / #  uname -a
    Linux archlinux 5.0.3 #2 SMP PREEMPT Mon Mar 25 10:27:13 CST 2019 x86_64 GNU/Linux
    / #
    
  5. Debuggen Sie den Linux-Kernel mit GDB

    ~/Projects/kernelbuild/linux-5.0.3 ➭ gdb vmlinux
    ...
    (gdb) target remote localhost:1234
    Remote debugging using localhost:1234
    0xffffffff89a4b852 in ?? ()
    (gdb) break start_kernel
    Breakpoint 1 at 0xffffffff826ccc08
    (gdb)
    Display all 190 possibilities? (y or n)
    (gdb) info functions
    All defined functions:
    
    Non-debugging symbols:
    0xffffffff81000000  _stext
    0xffffffff81000000  _text
    0xffffffff81000000  startup_64
    0xffffffff81000030  secondary_startup_64
    0xffffffff810000e0  verify_cpu
    0xffffffff810001e0  start_cpu0
    0xffffffff810001f0  __startup_64
    0xffffffff81000410  pvh_start_xen
    0xffffffff81001000  hypercall_page
    0xffffffff81001000  xen_hypercall_set_trap_table
    0xffffffff81001020  xen_hypercall_mmu_update
    0xffffffff81001040  xen_hypercall_set_gdt
    0xffffffff81001060  xen_hypercall_stack_switch
    0xffffffff81001080  xen_hypercall_set_callbacks
    0xffffffff810010a0  xen_hypercall_fpu_taskswitch
    0xffffffff810010c0  xen_hypercall_sched_op_compat
    0xffffffff810010e0  xen_hypercall_platform_op
    
0
debug