Anwendungsentwicklung mit QEMU #2

29. August 2019

Skriptfehler ausbügeln

Es hat ein gutes Stück gedauert, aber nun habe ich endlich einen funktionierenden Aufbau. Mein Fehler bestand in einem fehlerhaften Aufruf QEMUs.

#!/bin/sh

qemu-system-arm \
        -M vexpress-a9 \
        -kernel QemuArmVexpress/images/zImage \
        -dtb QemuArmVexpress/images/vexpress-v2p-ca9.dtb \
        -drive file=QemuArmVexpress/images/rootfs.ext2,if=sd,format=raw \
        -append "rw console=ttyAMA0 console=tty root=/dev/mmcblk0" \
        -cpu cortex-a9 \
        -m 32 \
        -serial stdio \
        -net user,hostfwd=tcp::2222-:22 \
        -nic user,hostfwd=tcp::2459-:2459 \
        -name VexpressArm

Von den hervorgehobenen Zeilen funktioniert nur die erste. Die zweite lässt folgende Warnung erscheinen

$ ./QemuArmVexpressBuildroot.sh
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
qemu-system-arm: warning: hub 0 with no nics
Booting Linux on physical CPU 0x0
..

und so schlimm wird sie schon nicht sein. Das System bootet und man kann sich über SSH verbinden. Ein Aufrufen von Internetseiten aus der virtuellen Umgebung heraus liefert das gewünschte Ergebnis, damit sollte doch das Netzwerk wie gewünscht funktionieren. Sollte. Der Port 2459 wird nicht durchgereicht und zwischen dem gdbserver und dem gdb kommt keine Verbindung zustande. Die Fehlersuche wird dank der Fehlermeldung erschwert,

Failed to execute MI command:
-target-select remote localhost:2459
Error message from debugger back end:
Remote replied unexpectedly to 'vMustReplyEmpty': timeout

denn diese führt unter anderem zu diesem Hinweis und der suggeriert das Problem läge in der Kommunikation zwischen dem gdbserver und gdb. Das stimmt allerdings nicht, denn das Problem liegt im fehlerhaften Aufruf QEMUs. Der Port 2459 wird schlichtweg nicht durchgereicht und damit endet der Verbindungsversuch mit einem Timeout. Ändert man den Aufruf wie folgt ab,

#!/bin/sh

qemu-system-arm \
        -M vexpress-a9 \
        -kernel QemuArmVexpress/images/zImage \
        -dtb QemuArmVexpress/images/vexpress-v2p-ca9.dtb \
        -drive file=QemuArmVexpress/images/rootfs.ext2,if=sd,format=raw \
        -append "rw console=ttyAMA0 console=tty root=/dev/mmcblk0" \
        -cpu cortex-a9 \
        -m 32 \
        -serial stdio \
        -nic user,hostfwd=tcp::2222-:22,hostfwd=tcp::2459-:2459 \
        -name VexpressArm

wird der Port weitergeleitet und die Verbindung klappt.

dropbear durch openssh-server ersetzen

Eclipse liefert die kompilierten Programme standardmäßig mit SFTP aus. Das ist Teil von OpenSSH aber nicht von Dropbear. Jetzt könnte man entweder innerhalb der IDE Anpassungen vornehmen, damit das Ausliefern der Anwendung anders vonstattengeht, oder man nimmt für die Entwicklung einfach OpenSSH anstelle von Dropbear.

→ Target packages → Networking applications ──────────────────────────────────────────
 ┌───────────────────────────── Networking applications ─────────────────────────────┐
 │ ┌────↑(-)───────────────────────────────────────────────────────────────────────┐ │
 │ │    [ ] dhcpdump                                                               │ │
 │ │    [ ] dnsmasq                                                                │ │
 │ │    [ ] drbd-utils                                                             │ │
 │ │    [ ] dropbear                                                               │ │
 │ │    [ ] ebtables                                                               │ │
 │ │        *** ejabberd needs erlang, toolchain w/ C++ ***                        │ │
 │ │    [ ] ethtool                                                                │ │
 │ │    [ ] faifa                                                                  │ │
 │ │    [ ] fastd                                                                  │ │
 │ │    (..)                                                                       │ │
 │ │    [ ] openresolv                                                             │ │
 │ │    [*] openssh                                                                │ │
 │ │    [ ] openswan                                                               │ │
 │ │    [ ] openvpn                                                                │ │
 │ │    [ ] p910nd                                                                 │ │
 │ └────↓(+)───────────────────────────────────────────────────────────────────────┘ │
 ├───────────────────────────────────────────────────────────────────────────────────┤
 │             <Select>    < Exit >    < Help >    < Save >    < Load >              │
 └───────────────────────────────────────────────────────────────────────────────────┘

Cross-Compile-Umgebung auswählen

Damit lassen sich Images gut reproduzieren, aber da im Fehlerfall ein make clean oft die “schnellste” Lösung ist, dauert der nachfolgende Buildprozess, da der Compiler erst wieder gebaut werden muss, deutlich länger. Solange die Toolchain nicht innerhalb der (typischen) Systempfade abgelegt ist, muss die Entwicklungsumgebung i.d.R. darüber informiert werden. Auf den ersten Blick scheint es verlockend die von der Distribution mitgelieferte Crosscompilation-Umgebung zu verwenden, aber

We also do not support using the distribution toolchain (i.e. the gcc/binutils/C library installed by your distribution) as the toolchain to build software for the target. This is because your distribution toolchain is not a “pure” toolchain (i.e. only with the C/C++ library), so we cannot import it properly into the Buildroot build environment. So even if you are building a system for a x86 or x86_64 target, you have to generate a cross-compilation toolchain with Buildroot or crosstool-NG.

Quelle

diese ist nicht “rein” (besser schlank) genug und kann daher nicht verwendet werden. Alternativ kann eine vorgefertigte Toolchain von Linaro oder ARM genutzt werden. Wovon bei Linaro die Laufzeitumgebung, das Systemverzeichnis und das Kompilerpaket für das Host-System in der passenden Architektur (x86_64, i686), benötigt werden, während bei ARM alles in einem Gesamtpaket enthalten ist. Die entsprechenden Pfade müssen auf diesem Weg zwar auch der Entwicklungsumgebung bekannt gemacht werden, aber da diese Toolchain von verschiedenen Builds genutzt werden wird, entsteht dieser “Aufwand” nur einmal. Externe Pakete werden für gewöhnlich nach /opt/ installiert bzw. entpackt und die interne Toolchain befindet sich im Projektverzeichnis. Deren Aufbauten sind nachfolgend aufgeführt.

→ Toolchain ──────────────────────────────────────────────────────────────────────────
 ┌──────────────────────────────────── Toolchain ────────────────────────────────────┐
 │ ┌───────────────────────────────────────────────────────────────────────────────┐ │  
 │ │        Toolchain type (Buildroot toolchain)  --->                             │ │  
 │ │        *** Toolchain Buildroot Options ***                                    │ │  
 │ │    (buildroot) custom toolchain vendor name                                   │ │  
 │ │        C library (uClibc-ng)  --->                                            │ │  
 │ │        *** Kernel Header Options ***                                          │ │  
 │ │        Kernel Headers (Same as kernel being built)  --->                      │ │  
 │ │        Custom kernel headers series (5.1.x)  --->                             │ │  
 │ │        *** uClibc Options ***                                                 │ │  
 │ │    (package/uclibc/uClibc-ng.config) uClibc configuration file to use?        │ │  
 │ │    ()  Additional uClibc configuration fragment files                         │ │  
 │ │    [*] Enable WCHAR support                                                   │ │  
 │ │    [ ] Enable toolchain locale/i18n support                                   │ │  
 │ │        Thread library implementation (Native POSIX Threading (NPTL))  --->    │ │  
 │ │    [*] Thread library debugging                                               │ │  
 │ │    [ ] Enable stack protection support                                        │ │  
 │ │    [*] Compile and install uClibc utilities                                   │ │  
 │ │        *** Binutils Options ***                                               │ │  
 │ │        Binutils Version (binutils 2.31.1)  --->                               │ │  
 │ │    ()  Additional binutils options                                            │ │  
 │ │        *** GCC Options ***                                                    │ │  
 │ │        GCC compiler Version (gcc 7.x)  --->                                   │ │  
 │ │    ()  Additional gcc options                                                 │ │  
 │ │    [*] Enable C++ support                                                     │ │  
 │ │    [ ] Enable Fortran support                                                 │ │  
 │ │    [ ] Enable compiler link-time-optimization support                         │ │  
 │ │    [ ] Enable compiler OpenMP support                                         │ │  
 │ │    [ ] Enable graphite support                                                │ │  
 │ │        *** Host GDB Options ***                                               │ │  
 │ │    [*] Build cross gdb for the host                                           │ │  
 │ │    [*]   TUI support                                                          │ │  
 │ └────↓(+)───────────────────────────────────────────────────────────────────────┘ │  
 ├───────────────────────────────────────────────────────────────────────────────────┤  
 │             <Select>    < Exit >    < Help >    < Save >    < Load >              │  
 └───────────────────────────────────────────────────────────────────────────────────┘  
$ tree -L 2
.
├── build
├── host
│   ├── arm-buildroot-linux-uclibcgnueabihf
│   ├── bin
│   ├── etc
│   ├── include
│   ├── lib
│   ├── lib64 -> lib
│   ├── libexec
│   ├── sbin
│   ├── share
│   └── usr -> .
├── images
│   ├── rootfs.ext2
│   ├── vexpress-v2p-ca9.dtb
│   └── zImage
├── Makefile
├── staging -> ../host/arm-buildroot-linux-uclibcgnueabihf/sysroot
└── target
    ├── bin
    ├── dev
    ├── etc
    ├── lib
    ├── lib32 -> lib
    ├── linuxrc -> bin/busybox
    ├── media
    ├── mnt
    ├── opt
    ├── proc
    ├── root
    ├── run
    ├── sbin
    ├── sys
    ├── THIS_IS_NOT_YOUR_ROOT_FILESYSTEM
    ├── tmp
    ├── usr
    └── var
→ Toolchain ───────────────────────────────────────────────────────────────────────────────────
 ┌──────────────────────────────────── Toolchain ─────────────────────────────────────────────┐
 │ ┌────────────────────────────────────────────────────────────────────────────────────────┐ │
 │ │        Toolchain type (External toolchain)  --->                                       │ │
 │ │        *** Toolchain External Options ***                                              │ │
 │ │        Toolchain (Linaro ARM 2018.05)  --->                                            │ │
 │ │        Toolchain origin (Pre-installed toolchain)  --->                                │ │
 │ │    (/opt/linaro/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf) Toolchain path    │ │
 │ │    [ ] Copy gdb server to the Target                                                   │ │
 │ │        *** Host GDB Options ***                                                        │ │
 │ │    [*] Build cross gdb for the host                                                    │ │
 │ │    [ ]   TUI support                                                                   │ │
 │ │    [ ]   Python support                                                                │ │
 │ │    [ ]   Simulator support                                                             │ │
 │ │          GDB debugger Version (gdb 8.1.x)  --->                                        │ │
 │ │        *** Toolchain Generic Options ***                                               │ │
 │ │    [ ] Copy gconv libraries (NEW)                                                      │ │
 │ │    [*] Enable MMU support                                                              │ │
 │ │    ()  Target Optimizations                                                            │ │
 │ │    ()  Target linker options                                                           │ │
 │ │    [ ] Register toolchain within Eclipse Buildroot plug-in                             │ │
 │ │                                                                                        │ │
 │ └────────────────────────────────────────────────────────────────────────────────────────┘ │
 ├────────────────────────────────────────────────────────────────────────────────────────────┤
 │               <Select>    < Exit >    < Help >    < Save >    < Load >                     │
 └────────────────────────────────────────────────────────────────────────────────────────────┘
/opt/linaro $ tree -L 2
.
├── gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf
│   ├── arm-linux-gnueabihf
│   ├── bin
│   ├── gcc-linaro-7.4.1-2019.02-linux-manifest.txt
│   ├── include
│   ├── lib
│   ├── libexec
│   └── share
├── runtime-gcc-linaro-7.4.1-2019.02-arm-linux-gnueabihf
│   ├── lib
│   └── usr
└── sysroot-glibc-linaro-2.25-2019.02-arm-linux-gnueabihf
    ├── etc
    ├── lib
    ├── sbin
    ├── usr
    └── var
→ Toolchain ───────────────────────────────────────────────────────────────────────────────
 ┌──────────────────────────────────── Toolchain ─────────────────────────────────────────┐
 │ ┌────────────────────────────────────────────────────────────────────────────────────┐ │  
 │ │        Toolchain type (External toolchain)  --->                                   │ │  
 │ │        *** Toolchain External Options ***                                          │ │  
 │ │        Toolchain (Arm ARM 2018.11)  --->                                           │ │  
 │ │        Toolchain origin (Toolchain to be downloaded and installed)  --->           │ │  
 │ │    [ ] Copy gdb server to the Target (NEW)                                         │ │  
 │ │        *** Host GDB Options ***                                                    │ │  
 │ │    [*] Build cross gdb for the host                                                │ │  
 │ │    [*]   TUI support                                                               │ │  
 │ │    [ ]   Python support                                                            │ │  
 │ │    [ ]   Simulator support                                                         │ │  
 │ │          GDB debugger Version (gdb 8.1.x)  --->                                    │ │  
 │ │        *** Toolchain Generic Options ***                                           │ │  
 │ │    [ ] Copy gconv libraries (NEW)                                                  │ │  
 │ │    [*] Enable MMU support                                                          │ │  
 │ │    ()  Target Optimizations                                                        │ │  
 │ │    ()  Target linker options                                                       │ │  
 │ │    [*] Register toolchain within Eclipse Buildroot plug-in                         │ │  
 │ │                                                                                    │ │  
 │ └────────────────────────────────────────────────────────────────────────────────────┘ │  
 ├────────────────────────────────────────────────────────────────────────────────────────┤  
 │             <Select>    < Exit >    < Help >    < Save >    < Load >                   │  
 └────────────────────────────────────────────────────────────────────────────────────────┘  
/opt/arm $ tree -L 2
.
├── gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf
│   ├── 8.3-2019.03-x86_64-arm-linux-gnueabihf-manifest.txt
│   ├── arm-linux-gnueabihf
│   ├── bin
│   ├── include
│   ├── lib
│   ├── lib64
│   ├── libexec
│   └── share
├── runtime-gcc-8.3-2019.03-x86_64-arm-linux-gnueabihf
│   ├── lib
│   └── usr
└── sysroot-glibc-8.3-2019.03-x86_64-arm-linux-gnueabihf
    ├── etc
    ├── lib
    ├── sbin
    ├── usr
    └── var

Damit die Anwendung auf der Zielplattform ausführbar ist, muss der Quelltext vom passenden Compiler mit den richtigen Umgebungsvariaben übersetzt werden. Im Folgenden ist das Einstellen des Compilers etc. für ein Makefile und für eine Entwicklungsumgebung gezeigt.

Das Makefile stammt [nicht von mir](https://github.com/ricorx7/ARM-Cross-Compile-Makefile/blob/master/makefile.mak), ich habe es lediglich etwas angepasst. Verwendet wird hier die interne Toolchain. Soll eine externe genommen werden, so müssen die Compiler-Pfade entsprechend gesetzt werden. Bei der Fehlersuche hilft `make -l`, das gibt die Befehle nur aus ohne sie auszuführen. Mit `make BUILD=devel` wird das Projekt mit Debug-Symbolen übersetzt, fehlt noch die händische Übertragung auf die Zielplattform, das Starten des `gdbserver`s auf dieser und der Verbindungsaufbau vom `gdb` mit dem Server. Um all das ließe sich das Makefile noch erweitern, aber Debuggen mit IDEs ist angenehmer und sie nehmen einem diese Schritte mittlerweile ab.
# Makefile
# Created by Rico Castelo <rico.castelo at gmail dot com>
# Free to Use

BUILDROOT_HOME=/home/user/projects/bootlin.com/QemuArmVexpress

PRJ_ROOT_DIR := $(shell pwd)
#ANOTHER_PROJECT_HOME := /home/user/AnotherProject
#YET_ANOTHER_PROJECT_HOME := /home/user/YetAnotherProject

# Target Name
TARGET_NAME := HelloWorld
PROJECT_TYPE := app

#Version Number
MAJOR := 0
MINOR := 08

#Include directories
#INCLUDES_SRC = -I$(ANOTHER_PROJECT_HOME) -I$(YET_ANOTHER_PROJECT_HOME)/include
INCLUDES_SRC = 

#Libraries
#LIBRARIES := -lboost_filesystem -lboost_thread -lboost_system -ldl -L$(ANOTHER_PROJECT_HOME) -lAnotherProjectLibrary -lpthread
LIBRARIES := 

#Add more App Object files
OBJFILES :=

#Add more Dependency files
#These files are generated automatically.  This is only needed to delete them all
DEPFILES :=

# Doxygen Configuration file
DOXYGEN_CONFIG := doxyfile

# ----------------------------------------------------------------------------
# DO NOT MODIFY BELOW
# ----------------------------------------------------------------------------
#Set for Debug mode or non-debug
BUILD := rel

#Set Architecture
ARCH := arm

#Compilers
ifeq ($(ARCH),arm)
CC := $(BUILDROOT_HOME)/host/bin/arm-buildroot-linux-uclibcgnueabihf-g++
GCC := $(BUILDROOT_HOME)/host/bin/arm-buildroot-linux-uclibcgnueabihf-gcc
CFLAGS := --sysroot=$(BUILDROOT_HOME)/staging
else
CC := g++
GCC := gcc
CFLAGS := 
endif

#Set the file extension and prefix if lib
ifeq ($(PROJECT_TYPE),lib)
TARGET_PREFIX = lib
TARGET_POSTFIX = .so
CC += -shared
else
TARGET_PREFIX =
TARGET_POSTFIX =
endif

#BuildTool flags
ifeq ($(BUILD),rel)
DEBUGFLAGS_Assembler =
DEBUGFLAGS_C++-Compiler = -Os -Wall -Werror
DEBUGFLAGS_C++-Linker =
DEBUGFLAGS_C-Compiler = -Os -fomit-frame-pointer -D__USE_STRING_INLINES -pipe -Wall
DEBUGFLAGS_C-Linker =
DEBUGFLAGS_Librarian =
DEBUGFLAGS_Shared-Library-Linker =
else
DEBUGFLAGS_Assembler = -g
DEBUGFLAGS_C++-Compiler = -g -O0 -fno-omit-frame-pointer -pipe -Wall -DDEBUG
DEBUGFLAGS_C++-Linker = -g
DEBUGFLAGS_C-Compiler = -g -O0 -fno-omit-frame-pointer -pipe -Wall
DEBUGFLAGS_C-Linker = -g
DEBUGFLAGS_Librarian = -g
DEBUGFLAGS_Shared-Library-Linker = -g
endif
TARGET = $(TARGET_PREFIX)$(TARGET_NAME)$(TARGET_POSTFIX)
TARGET_VER = $(TARGET_PREFIX)$(TARGET_NAME)_$(MAJOR).$(MINOR)$(TARGET_POSTFIX)

#Global Build Macros
DEFINES +=

#Global Include directories
INCLUDES_SRC += -I$(PRJ_ROOT_DIR)/include

#Global Libraries
LIBRARIES +=

#Global App Object files
OBJFILES += $(patsubst %.cpp,%.o,$(wildcard *.cpp)) $(patsubst %.cpp,%.o,$(wildcard src/*.cpp))
OBJFILES += $(patsubst %.c,%.o,$(wildcard *.c)) $(patsubst %.c,%.o,$(wildcard src/*.c))

#Global Dependency files
#These files are generated automatically.  This is only needed to delete them all
DEPFILES += $(patsubst %.cpp,%.d,$(wildcard *.cpp)) $(patsubst %.cpp,%.d,$(wildcard src/*.cpp))
DEPFILES += $(patsubst %.c,%.d,$(wildcard *.c)) $(patsubst %.c,%.d,$(wildcard src/*.c))

#Compile object files
%.o: %.cpp
	$(GCC) $(CFLAGS) $(DEBUGFLAGS_C++-Compiler) $(INCLUDES_SRC) $(DEFINES) -c -fmessage-length=0 -Wold-style-cast -Woverloaded-virtual -o $@ $<

#Compile object files
#May need to replace $(CC) with $(GCC)
%.o: %.c
	$(GCC) $(CFLAGS) $(DEBUGFLAGS_C-Compiler) $(INCLUDES_SRC) $(DEFINES) -c -fmessage-length=0 -o $@ $<

#Build application
#Create two version of the file so when including the library you do not have to worry about a version
all: $(OBJFILES)
	$(GCC) $(CFLAGS) -o $(TARGET) $(OBJFILES) $(LIBRARIES)
#	$(GCC) $(CFLAGS) -o $(TARGET_VER) $(OBJFILES) $(LIBRARIES)
#	scp -P 2222 $(TARGET) root@localhost:/root

#Clean files
clean:
	rm -f $(OBJFILES) rm -f $(DEPFILES) rm -f $(TARGET) rm -rf $(TARGET_VER)

#Make Doxygen files
doxygen:
	cd docs && \
	doxygen $(DOXYGEN_CONFIG)

#Clean Doxygen files
clean_doxygen:
	rm -rf docs/html
	rm -rf docs/latex

#Help option
help:
	@echo
	@echo "  make [target] [OPTIONS]"
	@echo
	@echo " Targets:"
	@echo "     all             Builds the app.  This is the default target."
	@echo "     clean           Clean all the objects, apps and dependencies."
	@echo "     help            Prints this message."
	@echo "     doxygen         Create doxygen files"
	@echo "     doxygen_clean   Clean doxygen files"
	@echo " Options:"
	@echo "     BUILD=rel       Build a release build (default)"
	@echo "     BUILD=devel     Build a debug build"
	@echo "                     "
	@echo "     ARCH=arm        Build an ARM build (default)"
	@echo "     ARCH=x86        Build an X86 build"
	@echo "                     "
	@echo
Es wird ein neues Projekt erstellt. `File --> New --> C/C++ Project` im erscheinenden Fenster `C Managed Build` bzw. `C++ Managed Build` auswählen, einen Projektnamen und die Toolchain angeben, ebenso die Buildtypen (Debug, Release) und zuletzt die Toolchain spezifizieren. Bildlich dargestellt sollte der Vorgang in etwa so aussehen. ![Neues C-Projekt](/images/Eclipse_CProject.png) ![Cross-Compile Command](/images/Eclipse_CrossGCCCommand.png) Mit einem mächtigen [Hallo-Welt](https://de.wikipedia.org/wiki/Hallo-Welt-Programm)-Programm kann die Funktion zügig nachvollzogen werden. Nachdem dieses übersetzt wurde erscheint im Unterordner `Binaries` die Anwendung und in eckigen Klammern ist die Architektur angegeben. ![Binaries](/images/Eclipse_ScreenshotBinaries.png) Soweit so gut, fehlt noch die Übertragung der Anwendung auf die Zielplattform und das Debuggen. Dazu erstellt man eine Debug Konfiguration wie in den nachfolgenden Bildern gezeigt. ![Debug Configuration - Main](/images/Eclipse_DebugConfigurationsMain.png) Unter `C/C++ Remote Application` erstellt man eine neue Debug Konfiguration und am wichtigsten ist die Angabe von `Remote Host` beim Punkt `Connection`. Dann spezifiziert man diese über `Edit...` wie folgt genauer. ![Debug Configuration - Debugger - Main](/images/Eclipse_EditRemoteConnection.png) Wichtig ist hierbei die Angabe des richtigen SSH-Ports `2222`. Im Beispiel ist die Authentifizierung mittels Benutzername und Passwort gewählt, alternativ kann diese auch mittels Schlüsseln erfolgen. Jetzt kann im vorherigen Fenster bei `Remote Absolute File Path for C/C++ Application:` mittels `Browse` der Pfad auf der Zielplattform ausgewählt werden. Da die Applikation jedoch noch nicht übertragen wurde, klappt das nur so halb. ![Debug Configuration - Debugger - Main](/images/Eclipse_DebugConfigurationDebuggerMain.png) Als Debugger kann der Debugger des Systems gewählt werden, allerdings das Modell `gdb-multiarch` (findet sich sicherlich im Paketmanager der Distribution), dieser wird über die `gdbinit`-Datei über die Systemumgebung unterrichtet, und ![Debug Configuration - Debugger - Gdb-Settings](/images/Eclipse_DebugConfigurationsDebuggerGdbSettings.png) damit die Verbindung mit dem Ziel klappt, muss der richtige Port `2459` angegeben werden. Nun kann eine Debug-Session gestartet und die Applikation bequem gedebuggt werden. Vorausgesetzt die Zielplattform läuft innerhalb von [QEMU](https://www.qemu.org/blog/).

csv nach png

15. Oktober 2019

Debian in Qemu unter Windows

30. August 2019

Anwendungsentwicklung mit QEMU

19. Juni 2019