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:
Mike Gerdts 2022-12-16 17:19:28 -06:00 committed by Jim Harris
parent 531258aa51
commit adc2ca50e9
2 changed files with 116 additions and 0 deletions

View File

@ -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.

View File

@ -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