Add a backtrace_on_error meson feature (enabled with
--enable-backtrace-on-error) that compiles system binaries with
-rdynamic option and prints a function backtrace on error to stderr.

Example output by adding an unconditional error_setg on error_abort in 
hw/arm/boot.c:

  ./qemu-system-aarch64(+0x13b4a2c) [0x55d015406a2c]
  ./qemu-system-aarch64(+0x13b4abd) [0x55d015406abd]
  ./qemu-system-aarch64(+0x13b4d49) [0x55d015406d49]
  ./qemu-system-aarch64(error_setg_internal+0xe7) [0x55d015406f62]
  ./qemu-system-aarch64(arm_load_dtb+0xbf) [0x55d014d7686f]
  ./qemu-system-aarch64(+0xd2f1d8) [0x55d014d811d8]
  ./qemu-system-aarch64(notifier_list_notify+0x44) [0x55d01540a282]
  ./qemu-system-aarch64(qdev_machine_creation_done+0xa0) [0x55d01476ae17]
  ./qemu-system-aarch64(+0xaa691e) [0x55d014af891e]
  ./qemu-system-aarch64(qmp_x_exit_preconfig+0x72) [0x55d014af8a5d]
  ./qemu-system-aarch64(qemu_init+0x2a89) [0x55d014afb657]
  ./qemu-system-aarch64(main+0x2f) [0x55d01521e836]
  /lib/x86_64-linux-gnu/libc.so.6(+0x29ca8) [0x7f3033d67ca8]
  /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x85) [0x7f3033d67d65]
  ./qemu-system-aarch64(_start+0x21) [0x55d0146814f1]

  Unexpected error in arm_load_dtb() at ../hw/arm/boot.c:529:

For qemu-system-aarch64, this adds an additional 2MB to the binary size
so this is not enabled by default. I also only tested this on Linux, it
might not be portable.

Signed-off-by: Manos Pitsidianakis <manos.pitsidiana...@linaro.org>
---
 meson.build                   |  3 +++
 meson_options.txt             |  2 ++
 scripts/meson-buildoptions.sh |  4 ++++
 util/error.c                  | 17 +++++++++++++++++
 4 files changed, 26 insertions(+)

diff --git a/meson.build b/meson.build
index 
e53cd5b413847f33c972540e1f67a092164a200d..5d6ec5a5d5cb4c176bb32450f2adf85fc4963105
 100644
--- a/meson.build
+++ b/meson.build
@@ -2649,6 +2649,7 @@ config_host_data.set('CONFIG_DEBUG_STACK_USAGE', 
get_option('debug_stack_usage')
 config_host_data.set('CONFIG_DEBUG_TCG', get_option('debug_tcg'))
 config_host_data.set('CONFIG_DEBUG_REMAP', get_option('debug_remap'))
 config_host_data.set('CONFIG_QOM_CAST_DEBUG', get_option('qom_cast_debug'))
+config_host_data.set('CONFIG_BACKTRACE', get_option('backtrace_on_error'))
 config_host_data.set('CONFIG_REPLICATION', get_option('replication').allowed())
 config_host_data.set('CONFIG_FSFREEZE', qga_fsfreeze)
 config_host_data.set('CONFIG_FSTRIM', qga_fstrim)
@@ -4454,6 +4455,7 @@ foreach target : target_dirs
     endif
 
     emulator = executable(exe_name, exe['sources'],
+               export_dynamic: get_option('backtrace_on_error'),
                install: true,
                c_args: c_args,
                dependencies: arch_deps + exe['dependencies'],
@@ -4714,6 +4716,7 @@ if 'simple' in get_option('trace_backends')
   summary_info += {'Trace output file': get_option('trace_file') + '-<pid>'}
 endif
 summary_info += {'QOM debugging':     get_option('qom_cast_debug')}
+summary_info += {'Backtrace support':     get_option('backtrace_on_error')}
 summary_info += {'Relocatable install': get_option('relocatable')}
 summary_info += {'vhost-kernel support': have_vhost_kernel}
 summary_info += {'vhost-net support': have_vhost_net}
diff --git a/meson_options.txt b/meson_options.txt
index 
dd335307505fb52c5be469aa4fab8883c93ec5c9..450c17349263429e59413b0c483c2d52db13325e
 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -368,6 +368,8 @@ option('debug_stack_usage', type: 'boolean', value: false,
        description: 'measure coroutine stack usage')
 option('qom_cast_debug', type: 'boolean', value: true,
        description: 'cast debugging support')
+option('backtrace_on_error', type: 'boolean', value: false,
+       description: 'print backtrace on error')
 option('slirp_smbd', type : 'feature', value : 'auto',
        description: 'use smbd (at path --smbd=*) in slirp networking')
 
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 
d559e260ed17e50a423aa25b27a86777489565d7..0dd28c93e4d8bd24f7343745c6462aa5d9a603ee
 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -22,6 +22,8 @@ meson_options_help() {
   printf "%s\n" '  --docdir=VALUE           Base directory for documentation 
installation'
   printf "%s\n" '                           (can be empty) [share/doc]'
   printf "%s\n" '  --enable-asan            enable address sanitizer'
+  printf "%s\n" '  --enable-backtrace-on-error'
+  printf "%s\n" '                           print backtrace on error'
   printf "%s\n" '  --enable-block-drv-whitelist-in-tools'
   printf "%s\n" '                           use block whitelist also in tools 
instead of only'
   printf "%s\n" '                           QEMU'
@@ -251,6 +253,8 @@ _meson_option_parse() {
     --disable-gcov) printf "%s" -Db_coverage=false ;;
     --enable-lto) printf "%s" -Db_lto=true ;;
     --disable-lto) printf "%s" -Db_lto=false ;;
+    --enable-backtrace-on-error) printf "%s" -Dbacktrace_on_error=true ;;
+    --disable-backtrace-on-error) printf "%s" -Dbacktrace_on_error=false ;;
     --bindir=*) quote_sh "-Dbindir=$2" ;;
     --enable-blkio) printf "%s" -Dblkio=enabled ;;
     --disable-blkio) printf "%s" -Dblkio=disabled ;;
diff --git a/util/error.c b/util/error.c
index 
daea2142f30121abc46e5342526f5eec40ea246e..d834756abd563f4108b7599bb4da1e5dd85ec46c
 100644
--- a/util/error.c
+++ b/util/error.c
@@ -17,13 +17,28 @@
 #include "qemu/error-report.h"
 #include "qapi/error-internal.h"
 
+#ifdef CONFIG_BACKTRACE
+#include <execinfo.h>
+#endif /* CONFIG_BACKTRACE */
+
 Error *error_abort;
 Error *error_fatal;
 Error *error_warn;
 
+static inline void dump_backtrace(void)
+{
+#ifdef CONFIG_BACKTRACE
+    void *buffer[255] = { 0 };
+    const int calls =
+        backtrace(buffer, sizeof(buffer) / sizeof(void *));
+    backtrace_symbols_fd(buffer, calls, 2);
+#endif /* CONFIG_BACKTRACE */
+}
+
 static void error_handle(Error **errp, Error *err)
 {
     if (errp == &error_abort) {
+        dump_backtrace();
         if (err->func) {
             fprintf(stderr, "Unexpected error in %s() at %.*s:%d:\n",
                     err->func, err->src_len, err->src, err->line);
@@ -38,10 +53,12 @@ static void error_handle(Error **errp, Error *err)
         abort();
     }
     if (errp == &error_fatal) {
+        dump_backtrace();
         error_report_err(err);
         exit(1);
     }
     if (errp == &error_warn) {
+        dump_backtrace();
         warn_report_err(err);
     } else if (errp && !*errp) {
         *errp = err;

---
base-commit: a41280fd5b94c49089f7631c6fa8bb9c308b7962
change-id: 20250805-backtrace-e8e4c2490b46

--
γαῖα πυρί μιχθήτω


Reply via email to