qemu-devel
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]