Skip to content

Qemu debugging

Jamie C. Driver edited this page Apr 3, 2025 · 2 revisions

Many thanks to @trevarj for the below tips on debugging with qemu (see https://github.com/Blockstream/Jade/issues/225)

#!/bin/sh
# Must be at toplevel of jade/
pkill xtensa-esp-elf-gdb
pkill qemu-system-xtensa
# copy qemu config -- modified to enable logging
cp configs/sdkconfig_qemu_psram_webdisplay_larger_dbg.defaults sdkconfig.defaults

# build
idf.py build

# make flash image
esptool.py --chip esp32 merge_bin --fill-flash-size 4MB -o build/flash_image.bin \
  --flash_mode dio --flash_freq 40m --flash_size 4MB \
  0x9000 build/partition_table/partition-table.bin \
  0xe000 build/ota_data_initial.bin \
  0x1000 build/bootloader/bootloader.bin \
  0x10000 build/jade.bin

# copy efuse
cp main/qemu/qemu_efuse.bin build/qemu_efuse.bin

# set permission
chmod 777 build/qemu_efuse.bin build/flash_image.bin

# monitoring
# idf.py qemu \
#   --flash-file build/flash_image.bin \
#   --efuse-file main/qemu/qemu_efuse.bin \
#   --qemu-extra-args "-nic user,model=open_eth,id=lo0,hostfwd=tcp:0.0.0.0:30122-:30122,hostfwd=tcp:0.0.0.0:30121-:30121" \
#   monitor

# gdb debugging
idf.py qemu \
  --flash-file build/flash_image.bin \
  --efuse-file main/qemu/qemu_efuse.bin \
  --qemu-extra-args "-nic user,model=open_eth,id=lo0,hostfwd=tcp:0.0.0.0:30122-:30122,hostfwd=tcp:0.0.0.0:30121-:30121" \
  --gdb monitor

# open web display
# xdg-open http://localhost:30122 &

# in another terminal...
# idf.py gdb
# (gdb) b

NOTE: you can also make this change, and logging should appear in the qemu window, rather than being sent back over the tcp connection to the client:

  1. add -serial stdio to qemu-extra-args when running qemu.

  2. change logging to log to serial, even when connecting to qemu over tcp:

--- a/main/logging.c
+++ b/main/logging.c
@@ -7,7 +7,9 @@
 #include <string.h>
 
 static const size_t BUFFER_SIZE = 256;
+#ifndef CONFIG_ETH_USE_OPENETH
 static const size_t LOG_CBOR_OVERHEAD = 8;
+#endif
 static const char* TRUNCATE_TAIL = "...\n";
 
 // Writes logging messages to the serial interface output buffer, ensuring
@@ -25,6 +27,16 @@ int serial_logger(const char* message, va_list fmt)
         written = sizeof(buff) - 1;
     }
 
+#ifdef CONFIG_ETH_USE_OPENETH
+    // We're using a dedicated tcp socket for the rpc messages with the
+    // client so the serial interface is free for the logging messages
+    // and they can just be written verbatim
+    // This is the code path when running in qemu
+    jade_process_push_out_message((uint8_t*)buff, written, SOURCE_SERIAL);
+#else
+    // This is the code path when running an actual jade
+    // The logging messages have to share the serial interface with the rpc
+    // messages so we have to wrap them in cbor
     CborEncoder root_encoder;
     uint8_t cbor_buff[BUFFER_SIZE + LOG_CBOR_OVERHEAD];
     cbor_encoder_init(&root_encoder, cbor_buff, sizeof(cbor_buff), 0);
@@ -40,8 +52,6 @@ int serial_logger(const char* message, va_list fmt)
     const size_t towrite = cbor_encoder_get_buffer_size(&root_encoder, cbor_buff);
 
     jade_process_push_out_message((uint8_t*)cbor_buff, towrite, SOURCE_SERIAL);
-#if defined(CONFIG_FREERTOS_UNICORE) && defined(CONFIG_ETH_USE_OPENETH)
-    jade_process_push_out_message((uint8_t*)cbor_buff, towrite, SOURCE_QEMU_TCP);
 #endif
 
     return written;

Clone this wiki locally