mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-01 23:03:54 -06:00
Block layer patches
- Managing inactive nodes (enables QSD migration with shared storage) - Fix swapped values for BLOCK_IO_ERROR 'device' and 'qom-path' - vpc: Read images exported from Azure correctly - scripts/qemu-gdb: Support coroutine dumps in coredumps - Minor cleanups -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmek34IRHGt3b2xmQHJl ZGhhdC5jb20ACgkQfwmycsiPL9bDpxAAnTvwmdazAXG0g9GzqvrEB/+6rStjAsqE 9MTWV4WxyN41d0RXxN8CYKb8CXSiTRyw6r3CSGNYEI2eShe9e934PriSkZm41HyX n9Yh5YxqGZqitzvPtx62Ii/1KG+PcjQbfHuK1p4+rlKa0yQ2eGlio1JIIrZrCkBZ ikZcQUrhIyD0XV8hTQ2+Ysa+ZN6itjnlTQIG3gS3m8f8WR7kyUXD8YFMQFJFyjVx NrAIpLnc/ln9+5PZR9tje8U7XEn2KCgI5pgGaQnrd0h0G1H4ig8ogzYYnKTLhjU/ AmQpS8np8Tyg6S1UZTiekEq0VuAhThEQc5b3sGbmHWH/R2ABMStyf18oCBAkPzZ7 s6h+3XzTKKY2Q5Q3ZG/ANkUJjTNBhdj1fcaARvbSWsqsuk5CWX/I3jzvgihFtCSs eGu+b/bLeW6P7hu4qPHBcgLHuB1Fc7Rd2t4BoIGM1wcO2CeC9DzUKOiIMZOEJIh0 GGqCkEWDHgckDTakD4/vSqm0UDKt6FSlQC9ga/ILBY3IB5HpHoArY58selymy28i X7MgAvbjdsmNuUuXDZZOiObcFt3j8jlmwPJpPyzXPQIiPX1RXeBPRhVAEeZCKn6Z tfHr72SJdMeVOGXVTvOrJ2iW+4g03rPdmkDFCUhpOwo62RODq7ahvCIXsNf3nEFR rSB3T1M/8EM= =iQLP -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging Block layer patches - Managing inactive nodes (enables QSD migration with shared storage) - Fix swapped values for BLOCK_IO_ERROR 'device' and 'qom-path' - vpc: Read images exported from Azure correctly - scripts/qemu-gdb: Support coroutine dumps in coredumps - Minor cleanups # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmek34IRHGt3b2xmQHJl # ZGhhdC5jb20ACgkQfwmycsiPL9bDpxAAnTvwmdazAXG0g9GzqvrEB/+6rStjAsqE # 9MTWV4WxyN41d0RXxN8CYKb8CXSiTRyw6r3CSGNYEI2eShe9e934PriSkZm41HyX # n9Yh5YxqGZqitzvPtx62Ii/1KG+PcjQbfHuK1p4+rlKa0yQ2eGlio1JIIrZrCkBZ # ikZcQUrhIyD0XV8hTQ2+Ysa+ZN6itjnlTQIG3gS3m8f8WR7kyUXD8YFMQFJFyjVx # NrAIpLnc/ln9+5PZR9tje8U7XEn2KCgI5pgGaQnrd0h0G1H4ig8ogzYYnKTLhjU/ # AmQpS8np8Tyg6S1UZTiekEq0VuAhThEQc5b3sGbmHWH/R2ABMStyf18oCBAkPzZ7 # s6h+3XzTKKY2Q5Q3ZG/ANkUJjTNBhdj1fcaARvbSWsqsuk5CWX/I3jzvgihFtCSs # eGu+b/bLeW6P7hu4qPHBcgLHuB1Fc7Rd2t4BoIGM1wcO2CeC9DzUKOiIMZOEJIh0 # GGqCkEWDHgckDTakD4/vSqm0UDKt6FSlQC9ga/ILBY3IB5HpHoArY58selymy28i # X7MgAvbjdsmNuUuXDZZOiObcFt3j8jlmwPJpPyzXPQIiPX1RXeBPRhVAEeZCKn6Z # tfHr72SJdMeVOGXVTvOrJ2iW+4g03rPdmkDFCUhpOwo62RODq7ahvCIXsNf3nEFR # rSB3T1M/8EM= # =iQLP # -----END PGP SIGNATURE----- # gpg: Signature made Thu 06 Feb 2025 11:12:50 EST # gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6 # gpg: issuer "kwolf@redhat.com" # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (25 commits) block: remove unused BLOCK_OP_TYPE_DATAPLANE iotests: Add (NBD-based) tests for inactive nodes iotests: Add qsd-migrate case iotests: Add filter_qtest() nbd/server: Support inactive nodes block/export: Add option to allow export of inactive nodes block: Drain nodes before inactivating them block/export: Don't ignore image activation error in blk_exp_add() block: Support inactive nodes in blk_insert_bs() block: Add blockdev-set-active QMP command block: Add option to create inactive nodes block: Fix crash on block_resize on inactive node block: Don't attach inactive child to active node migration/block-active: Remove global active flag block: Inactivate external snapshot overlays when necessary block: Allow inactivating already inactive nodes block: Add 'active' field to BlockDeviceInfo block-backend: Fix argument order when calling 'qapi_event_send_block_io_error()' scripts/qemu-gdb: Support coroutine dumps in coredumps scripts/qemu-gdb: Simplify fs_base fetching for coroutines ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
f2ec48fefd
35 changed files with 1133 additions and 166 deletions
|
@ -45,3 +45,5 @@ coroutine.CoroutineBt()
|
|||
# Default to silently passing through SIGUSR1, because QEMU sends it
|
||||
# to itself a lot.
|
||||
gdb.execute('handle SIGUSR1 pass noprint nostop')
|
||||
# Always print full stack for python errors, easier to debug and report issues
|
||||
gdb.execute('set python print-stack full')
|
||||
|
|
|
@ -13,28 +13,9 @@ import gdb
|
|||
|
||||
VOID_PTR = gdb.lookup_type('void').pointer()
|
||||
|
||||
def get_fs_base():
|
||||
'''Fetch %fs base value using arch_prctl(ARCH_GET_FS). This is
|
||||
pthread_self().'''
|
||||
# %rsp - 120 is scratch space according to the SystemV ABI
|
||||
old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
|
||||
gdb.execute('call (int)arch_prctl(0x1003, $rsp - 120)', False, True)
|
||||
fs_base = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
|
||||
gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True)
|
||||
return fs_base
|
||||
|
||||
def pthread_self():
|
||||
'''Fetch pthread_self() from the glibc start_thread function.'''
|
||||
f = gdb.newest_frame()
|
||||
while f.name() != 'start_thread':
|
||||
f = f.older()
|
||||
if f is None:
|
||||
return get_fs_base()
|
||||
|
||||
try:
|
||||
return f.read_var("arg")
|
||||
except ValueError:
|
||||
return get_fs_base()
|
||||
'''Fetch the base address of TLS.'''
|
||||
return gdb.parse_and_eval("$fs_base")
|
||||
|
||||
def get_glibc_pointer_guard():
|
||||
'''Fetch glibc pointer guard value'''
|
||||
|
@ -65,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
|
||||
|
@ -88,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())
|
||||
|
||||
|
@ -120,10 +163,15 @@ class CoroutineBt(gdb.Command):
|
|||
|
||||
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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue