scripts: gdb needs a pretty printer for spinlocks
In debug builds, SPDK spinlocks will have stack traces that track where they were allocated, last locked, and last unlocked. This adds gdb pretty printers to make that information easily visible. See the updates in doc/gdb_macros.md for details. Signed-off-by: Mike Gerdts <mgerdts@nvidia.com> Change-Id: I4f903c588d9384c4005eec01348fa5c2d3cab5db Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16000 Reviewed-by: Jim Harris <james.r.harris@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
This commit is contained in:
parent
531258aa51
commit
adc2ca50e9
@ -125,6 +125,54 @@ nqn "nqn.2016-06.io.spdk.umgmt:cnode1", '\000' <repeats 191 times>
|
||||
ID 1
|
||||
~~~
|
||||
|
||||
Printing SPDK spinlocks:
|
||||
|
||||
In this example, the spinlock has been initialized and locked but has never been unlocked.
|
||||
After it is unlocked the first time the last unlocked stack will be present and the
|
||||
`Locked by spdk_thread` line will say `not locked`.
|
||||
|
||||
~~~{.sh}
|
||||
Breakpoint 2, spdk_spin_unlock (sspin=0x655110 <g_bdev_mgr+80>) at thread.c:2915
|
||||
2915 struct spdk_thread *thread = spdk_get_thread();
|
||||
(gdb) print *sspin
|
||||
$2 = struct spdk_spinlock:
|
||||
Locked by spdk_thread: 0x658080
|
||||
Initialized at:
|
||||
0x43e677 <spdk_spin_init+213> thread.c:2878
|
||||
0x404feb <_bdev_init+16> /build/spdk/spdk-review-public/lib/bdev/bdev.c:116
|
||||
0x44483d <__libc_csu_init+77>
|
||||
0x7ffff62c9d18 <__libc_start_main+120>
|
||||
0x40268e <_start+46>
|
||||
Last locked at:
|
||||
0x43e936 <spdk_spin_lock+436> thread.c:2909
|
||||
0x40ca9c <bdev_name_add+129> /build/spdk/spdk-review-public/lib/bdev/bdev.c:3855
|
||||
0x411a3c <bdev_register+641> /build/spdk/spdk-review-public/lib/bdev/bdev.c:6660
|
||||
0x412e1e <spdk_bdev_register+24> /build/spdk/spdk-review-public/lib/bdev/bdev.c:7171
|
||||
0x417895 <num_blocks_test+119> bdev_ut.c:878
|
||||
0x7ffff7bc38cb <run_single_test.constprop+379>
|
||||
0x7ffff7bc3b61 <run_single_suite.constprop+433>
|
||||
0x7ffff7bc3f76 <CU_run_all_tests+118>
|
||||
0x43351f <main+1439> bdev_ut.c:6295
|
||||
0x7ffff62c9d85 <__libc_start_main+229>
|
||||
0x40268e <_start+46>
|
||||
Last unlocked at:
|
||||
~~~
|
||||
|
||||
Print a single spinlock stack:
|
||||
|
||||
~~~{.sh}
|
||||
(gdb) print sspin->internal.lock_stack
|
||||
$1 = struct sspin_stack:
|
||||
0x40c6a1 <spdk_spin_lock+436> /build/spdk/spdk-review-public/lib/thread/thread.c:2909
|
||||
0x413f48 <spdk_spin+552> thread_ut.c:1831
|
||||
0x7ffff7bc38cb <run_single_test.constprop+379>
|
||||
0x7ffff7bc3b61 <run_single_suite.constprop+433>
|
||||
0x7ffff7bc3f76 <CU_run_all_tests+118>
|
||||
0x4148fa <main+547> thread_ut.c:1948
|
||||
0x7ffff62c9d85 <__libc_start_main+229>
|
||||
0x40248e <_start+46>
|
||||
~~~
|
||||
|
||||
## Loading The gdb Macros
|
||||
|
||||
Copy the gdb macros to the host where you are about to debug.
|
||||
|
@ -4,6 +4,7 @@
|
||||
#
|
||||
|
||||
import gdb
|
||||
import gdb.printing
|
||||
|
||||
|
||||
class SpdkTailqList(object):
|
||||
@ -307,6 +308,64 @@ class spdk_print_threads(SpdkPrintCommand):
|
||||
super(spdk_print_threads, self).__init__(name, threads)
|
||||
|
||||
|
||||
class SpdkSpinlockStackPrinter(object):
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_array(self):
|
||||
ret = []
|
||||
count = self.val['depth']
|
||||
for i in range(count):
|
||||
line = ''
|
||||
addr = self.val['addrs'][i]
|
||||
line += ' ' + str(addr)
|
||||
# Source and line (sal) only exists for objects with debug info
|
||||
sal = gdb.find_pc_line(int(addr))
|
||||
try:
|
||||
line += ' ' + str(sal.symtab.filename)
|
||||
line += ':' + str(sal.line)
|
||||
except AttributeError as e:
|
||||
pass
|
||||
ret.append(line)
|
||||
return ret
|
||||
|
||||
def to_string(self):
|
||||
return 'struct sspin_stack:\n' + '\n'.join(self.to_array())
|
||||
|
||||
def display_hint(self):
|
||||
return 'struct sspin_stack'
|
||||
|
||||
|
||||
class SpdkSpinlockPrinter(object):
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
thread = self.val['thread']
|
||||
internal = self.val['internal']
|
||||
s = 'struct spdk_spinlock:'
|
||||
s += '\n Locked by spdk_thread: '
|
||||
if thread == 0:
|
||||
s += 'not locked'
|
||||
else:
|
||||
s += str(thread)
|
||||
if internal != 0:
|
||||
stacks = [
|
||||
['Initialized', 'init_stack'],
|
||||
['Last locked', 'lock_stack'],
|
||||
['Last unlocked', 'unlock_stack']]
|
||||
for stack in stacks:
|
||||
s += '\n ' + stack[0] + ' at:\n '
|
||||
frames = SpdkSpinlockStackPrinter(internal[stack[1]])
|
||||
s += '\n '.join(frames.to_array())
|
||||
return s
|
||||
|
||||
def display_hint(self):
|
||||
return 'struct spdk_spinlock'
|
||||
|
||||
|
||||
class spdk_load_macros(gdb.Command):
|
||||
|
||||
def __init__(self):
|
||||
@ -316,12 +375,21 @@ class spdk_load_macros(gdb.Command):
|
||||
True)
|
||||
self.loaded = False
|
||||
|
||||
def load_pretty_printers(self):
|
||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("spdk_library")
|
||||
pp.add_printer('sspin_stack', '^sspin_stack$',
|
||||
SpdkSpinlockStackPrinter)
|
||||
pp.add_printer('spdk_spinlock', '^spdk_spinlock$', SpdkSpinlockPrinter)
|
||||
gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
if arg == '--reload':
|
||||
print('Reloading spdk information')
|
||||
reload = True
|
||||
else:
|
||||
reload = False
|
||||
# These can only load once
|
||||
self.load_pretty_printers()
|
||||
|
||||
if self.loaded and not reload:
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user