[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 3/3] scripts/qemu-gdb: Support coroutine dumps in coredumps
From: |
Peter Xu |
Subject: |
Re: [PATCH 3/3] scripts/qemu-gdb: Support coroutine dumps in coredumps |
Date: |
Wed, 11 Dec 2024 15:21:12 -0500 |
On Wed, Dec 11, 2024 at 03:17:39PM -0500, Peter Xu wrote:
> Dumping coroutines don't yet work with coredumps. Let's make it work.
>
> We still kept most of the old code because they can be either more
> flexible, or prettier. Only add the fallbacks when they stop working.
>
> Currently the raw unwind is pretty ugly, but it works, like this:
>
> (gdb) qemu bt
> Coroutine at 0x7fc474728748:
It didn't get commited.. I forgot to indent. It looks like this:
(gdb) qemu bt
#0 process_incoming_migration_co (opaque=0x0) at ../migration/migration.c:788
#1 0x000055cf3894d4d9 in coroutine_trampoline (i0=1565638480, i1=21967) at
../util/coroutine-ucontext.c:175
#2 0x00007fc481f72f40 in ??? () at /lib64/libc.so.6
#3 0x00007ffc0c74a520 in ??? ()
#4 0x0000000000000000 in ??? ()
Coroutine at 0x7fc474728748:
#0 qemu_coroutine_switch + 120
#1 qemu_aio_coroutine_enter + 357
#2 qemu_coroutine_enter + 35
#3 migration_incoming_process + 44
#4 migration_ioc_process_incoming + 491
#5 migration_channel_process_incoming + 146
#6 socket_accept_incoming_migration + 119
#7 qio_net_listener_channel_func + 132
#8 qio_channel_fd_source_dispatch + 79
#9 g_main_context_dispatch_unlocked.lto_priv + 316
#10 g_main_context_dispatch + 37
#11 glib_pollfds_poll + 91
#12 os_host_main_loop_wait + 129
#13 main_loop_wait + 204
#14 qemu_main_loop + 42
#15 qemu_default_main + 20
#16 main + 41
#17 __libc_start_call_main + 120
#18 __libc_start_main_impl + 139
>
> Signed-off-by: Peter Xu <peterx@redhat.com>
> ---
> scripts/qemugdb/coroutine.py | 50 +++++++++++++++++++++++++++++++-----
> 1 file changed, 43 insertions(+), 7 deletions(-)
>
> diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py
> index 20f76ed37b..b29ee16205 100644
> --- a/scripts/qemugdb/coroutine.py
> +++ b/scripts/qemugdb/coroutine.py
> @@ -46,9 +46,30 @@ def get_jmpbuf_regs(jmpbuf):
> 'r15': jmpbuf[JB_R15],
> 'rip': glibc_ptr_demangle(jmpbuf[JB_PC], pointer_guard) }
>
> -def bt_jmpbuf(jmpbuf):
> - '''Backtrace a jmpbuf'''
> - regs = get_jmpbuf_regs(jmpbuf)
> +def symbol_lookup(addr):
> + # Example: "__clone3 + 44 in section .text of /lib64/libc.so.6"
> + result = gdb.execute(f"info symbol {hex(addr)}", to_string=True).strip()
> + return result.split(" in ")[0]
> +
> +def dump_backtrace(regs):
> + '''
> + Backtrace dump with raw registers, mimic GDB command 'bt'.
> + '''
> + # Here only rbp and rip that matter..
> + rbp = regs['rbp']
> + rip = regs['rip']
> + i = 0
> +
> + while rbp:
> + print(f"#{i}\t{symbol_lookup(rip)}")
> + rip = gdb.parse_and_eval(f"*(uint64_t *)(uint64_t)({hex(rbp)} + 8)")
> + rbp = gdb.parse_and_eval(f"*(uint64_t *)(uint64_t)({hex(rbp)})")
> + i += 1
> +
> +def dump_backtrace_live(regs):
> + '''
> + Backtrace dump with gdb's 'bt' command, only usable in a live session.
> + '''
> old = dict()
>
> # remember current stack frame and select the topmost
> @@ -69,6 +90,17 @@ def bt_jmpbuf(jmpbuf):
>
> selected_frame.select()
>
> +def bt_jmpbuf(jmpbuf):
> + '''Backtrace a jmpbuf'''
> + regs = get_jmpbuf_regs(jmpbuf)
> + try:
> + # This reuses gdb's "bt" command, which can be slightly prettier
> + # but only works with live sessions.
> + dump_backtrace_live(regs)
> + except:
> + # If above doesn't work, fallback to poor man's unwind
> + dump_backtrace(regs)
> +
> def co_cast(co):
> return co.cast(gdb.lookup_type('CoroutineUContext').pointer())
>
> @@ -101,10 +133,14 @@ def invoke(self, arg, from_tty):
>
> gdb.execute("bt")
>
> - if gdb.parse_and_eval("qemu_in_coroutine()") == False:
> - return
> -
> - co_ptr = gdb.parse_and_eval("qemu_coroutine_self()")
> + try:
> + # This only works with a live session
> + co_ptr = gdb.parse_and_eval("qemu_coroutine_self()")
> + if co_ptr == False:
> + return
> + except:
> + # Fallback to use hard-coded ucontext vars if it's coredump
> + co_ptr = gdb.parse_and_eval("co_tls_current")
>
> while True:
> co = co_cast(co_ptr)
> --
> 2.47.0
>
--
Peter Xu