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.
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.
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:
init
- nur ausführbare Abbildung: https://unix.stackexchange.com/questions/122717/custom-linux-distro-that-runs-just-one-program-nothing-else/238579#238579Dann 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:
nokaslr
: https://unix.stackexchange.com/questions/397939/turning-off-kaslr-to-debug-linux-kernel-using-qemu-and-gdb/421287#421287Bekannte Einschränkungen:
-O0
: Wie kann ich den Linux-Kernel auf -O0 de-optimieren und mit -O0 kompilieren?max-completions
fix: Tab-Vervollständigungs-Interrupt für große Binärdateien durchbrennen Wahrscheinlich einige Eckpunkte, die in diesem Patch nicht behandelt wurden. Ein ulimit -Sv 500000
ist also eine kluge Aktion vor dem Debuggen. Speziell gesprengt, als ich die Registerkarte file<tab>
für das filename
-Argument von sys_execve
wie folgt abgeschlossen habe: https://stackoverflow.com/a/42290593/895245 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
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.
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/
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 ).
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).
Installieren Sie GDB und Qemu
Sudo pacman -S gdb qemu
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
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
/ #
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