From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, qemu-devel@nongnu.org
Subject: [PULL 07/25] scripts/qemu-gdb: Support coroutine dumps in coredumps
Date: Mon, 10 Feb 2025 17:10:16 +0100 [thread overview]
Message-ID: <20250210161034.76494-8-kwolf@redhat.com> (raw)
In-Reply-To: <20250210161034.76494-1-kwolf@redhat.com>
From: Peter Xu <peterx@redhat.com>
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
#0 process_incoming_migration_co (opaque=0x0) at ../migration/migration.c:788
#1 0x000055ae6c0dc4d9 in coroutine_trampoline (i0=-1711718576, i1=21934) at ../util/coroutine-ucontext.c:175
#2 0x00007f9f59d72f40 in ??? () at /lib64/libc.so.6
#3 0x00007ffd549214a0 in ??? ()
#4 0x0000000000000000 in ??? ()
Coroutine at 0x7f9f4c57c748:
#0 0x55ae6c0dc9a8 in qemu_coroutine_switch<+120> () at ../util/coroutine-ucontext.c:321
#1 0x55ae6c0da2f8 in qemu_aio_coroutine_enter<+356> () at ../util/qemu-coroutine.c:293
#2 0x55ae6c0da3f1 in qemu_coroutine_enter<+34> () at ../util/qemu-coroutine.c:316
#3 0x55ae6baf775e in migration_incoming_process<+43> () at ../migration/migration.c:876
#4 0x55ae6baf7ab4 in migration_ioc_process_incoming<+490> () at ../migration/migration.c:1008
#5 0x55ae6bae9ae7 in migration_channel_process_incoming<+145> () at ../migration/channel.c:45
#6 0x55ae6bb18e35 in socket_accept_incoming_migration<+118> () at ../migration/socket.c:132
#7 0x55ae6be939ef in qio_net_listener_channel_func<+131> () at ../io/net-listener.c:54
#8 0x55ae6be8ce1a in qio_channel_fd_source_dispatch<+78> () at ../io/channel-watch.c:84
#9 0x7f9f5b26728c in g_main_context_dispatch_unlocked.lto_priv<+315> ()
#10 0x7f9f5b267555 in g_main_context_dispatch<+36> ()
#11 0x55ae6c0d91a7 in glib_pollfds_poll<+90> () at ../util/main-loop.c:287
#12 0x55ae6c0d9235 in os_host_main_loop_wait<+128> () at ../util/main-loop.c:310
#13 0x55ae6c0d9364 in main_loop_wait<+203> () at ../util/main-loop.c:589
#14 0x55ae6bac212a in qemu_main_loop<+41> () at ../system/runstate.c:835
#15 0x55ae6bfdf522 in qemu_default_main<+19> () at ../system/main.c:37
#16 0x55ae6bfdf55f in main<+40> () at ../system/main.c:48
#17 0x7f9f59d42248 in __libc_start_call_main<+119> ()
#18 0x7f9f59d4230b in __libc_start_main_impl<+138> ()
Signed-off-by: Peter Xu <peterx@redhat.com>
Message-ID: <20241212204801.1420528-4-peterx@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
scripts/qemugdb/coroutine.py | 79 +++++++++++++++++++++++++++++++++---
1 file changed, 73 insertions(+), 6 deletions(-)
diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py
index 20f76ed37b..e98fc48a4b 100644
--- a/scripts/qemugdb/coroutine.py
+++ b/scripts/qemugdb/coroutine.py
@@ -46,9 +46,60 @@ 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()
+ try:
+ if "+" in result:
+ (func, result) = result.split(" + ")
+ (offset, result) = result.split(" in ")
+ else:
+ offset = "0"
+ (func, result) = result.split(" in ")
+ func_str = f"{func}<+{offset}> ()"
+ except:
+ return f"??? ({result})"
+
+ # Example: Line 321 of "../util/coroutine-ucontext.c" starts at address
+ # 0x55cf3894d993 <qemu_coroutine_switch+99> and ends at 0x55cf3894d9ab
+ # <qemu_coroutine_switch+123>.
+ result = gdb.execute(f"info line *{hex(addr)}", to_string=True).strip()
+ if not result.startswith("Line "):
+ return func_str
+ result = result[5:]
+
+ try:
+ result = result.split(" starts ")[0]
+ (line, path) = result.split(" of ")
+ path = path.replace("\"", "")
+ except:
+ return func_str
+
+ return f"{func_str} at {path}:{line}"
+
+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:
+ # For all return addresses on stack, we want to look up symbol/line
+ # on the CALL command, because the return address is the next
+ # instruction instead of the CALL. Here -1 would work for any
+ # sized CALL instruction.
+ print(f"#{i} {hex(rip)} in {symbol_lookup(rip if i == 0 else rip-1)}")
+ 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 +120,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 +163,15 @@ def invoke(self, arg, from_tty):
gdb.execute("bt")
- if gdb.parse_and_eval("qemu_in_coroutine()") == False:
- return
+ try:
+ # This only works with a live session
+ co_ptr = gdb.parse_and_eval("qemu_coroutine_self()")
+ except:
+ # Fallback to use hard-coded ucontext vars if it's coredump
+ co_ptr = gdb.parse_and_eval("co_tls_current")
- co_ptr = gdb.parse_and_eval("qemu_coroutine_self()")
+ if co_ptr == False:
+ return
while True:
co = co_cast(co_ptr)
--
2.48.1
next prev parent reply other threads:[~2025-02-10 16:20 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-10 16:10 [PULL 00/25] Block layer patches Kevin Wolf
2025-02-10 16:10 ` [PULL 01/25] vpc: Split off vpc_ignore_current_size() helper Kevin Wolf
2025-02-10 16:10 ` [PULL 02/25] vpc: Read images exported from Azure correctly Kevin Wolf
2025-02-10 16:10 ` [PULL 03/25] block: Improve blk_get_attached_dev_id() docstring Kevin Wolf
2025-02-10 16:10 ` [PULL 04/25] block: Fix leak in send_qmp_error_event Kevin Wolf
2025-02-10 16:10 ` [PULL 05/25] scripts/qemu-gdb: Always do full stack dump for python errors Kevin Wolf
2025-02-10 16:10 ` [PULL 06/25] scripts/qemu-gdb: Simplify fs_base fetching for coroutines Kevin Wolf
2025-02-10 16:10 ` Kevin Wolf [this message]
2025-02-10 16:10 ` [PULL 08/25] block-backend: Fix argument order when calling 'qapi_event_send_block_io_error()' Kevin Wolf
2025-02-10 16:10 ` [PULL 09/25] block: Add 'active' field to BlockDeviceInfo Kevin Wolf
2025-02-10 16:10 ` [PULL 10/25] block: Allow inactivating already inactive nodes Kevin Wolf
2025-02-10 16:10 ` [PULL 11/25] block: Inactivate external snapshot overlays when necessary Kevin Wolf
2025-02-10 16:10 ` [PULL 12/25] migration/block-active: Remove global active flag Kevin Wolf
2025-02-10 16:10 ` [PULL 13/25] block: Don't attach inactive child to active node Kevin Wolf
2025-02-10 16:10 ` [PULL 14/25] block: Fix crash on block_resize on inactive node Kevin Wolf
2025-02-10 16:10 ` [PULL 15/25] block: Add option to create inactive nodes Kevin Wolf
2025-02-10 16:10 ` [PULL 16/25] block: Add blockdev-set-active QMP command Kevin Wolf
2025-02-10 16:10 ` [PULL 17/25] block: Support inactive nodes in blk_insert_bs() Kevin Wolf
2025-02-10 16:10 ` [PULL 18/25] block/export: Don't ignore image activation error in blk_exp_add() Kevin Wolf
2025-02-10 16:10 ` [PULL 19/25] block: Drain nodes before inactivating them Kevin Wolf
2025-02-10 16:10 ` [PULL 20/25] block/export: Add option to allow export of inactive nodes Kevin Wolf
2025-02-10 16:10 ` [PULL 21/25] nbd/server: Support " Kevin Wolf
2025-02-10 16:10 ` [PULL 22/25] iotests: Add filter_qtest() Kevin Wolf
2025-02-10 16:10 ` [PULL 23/25] iotests: Add qsd-migrate case Kevin Wolf
2025-02-10 16:10 ` [PULL 24/25] iotests: Add (NBD-based) tests for inactive nodes Kevin Wolf
2025-02-10 16:10 ` [PULL 25/25] block: remove unused BLOCK_OP_TYPE_DATAPLANE Kevin Wolf
2025-02-11 2:37 ` [PULL 00/25] Block layer patches Stefan Hajnoczi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250210161034.76494-8-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).