Skip to content

Commit 29e1701

Browse files
committed
scripts: gdb: Globbed all dbg scripts into dbg.gdb.py
This goes ahead and makes all dbg scripts available in dbg.gdb.py, via the magic of globbing __file__ relative, and dynamic python class generation. Probably one of the more evil scripts I've written, but this means we don't need to worry about dbg.gdb.py falling out-of-date when adding new dbg scripts. Not all of the dbg scripts are useful inside gdb, but most of them are. After all, what's cooler than this! (gdb) dbgrbyd -b4096 "disk" -t \ file->b.shrub.blocks[0] \ --trunk lfs3_rbyd_trunk(&file->b.shrub) rbyd 0x46.23a w2048, rev 00000000, size 629, cksum 8f5169e1 00000004: .-> 0-334 data w335 0 00000009: .-+-> 335 data w1 1 71 0000000e: | .-> 336 data w1 1 67 00000013: .-+-+-> 337 data w1 1 66 ... 00000144: | | | | .-> 350 data w1 1 74 0000019a: | | | | .-+-> 351 data w1 1 78 000001f5: | | | | | .-> 352-739 data w388 1 76 00000258: +-+-+-+-+-+-> 740-2047 data w1308 1 6c Note some tricks to help interact with bash and gdb: - Flags are passed as is (-b4096, -t, --trunk) - All non-flags are parsed as expressions (file->b.shrub.blocks[0]) - String expressions may be useful for paths and stuff ("./disk")
1 parent 090611a commit 29e1701

1 file changed

Lines changed: 121 additions & 78 deletions

File tree

scripts/dbg.gdb.py

Lines changed: 121 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,136 @@
11
#
2-
# hooks for gdb:
2+
# Hooks for gdb:
33
# (gdb) source ./scripts/dbg.gdb.py
44
#
55
#
66

7-
8-
# dbgerr
9-
class DbgErr(gdb.Command):
10-
"""Decode littlefs error codes. See -h/--help for more info."""
11-
12-
def __init__(self):
13-
super().__init__("dbgerr",
14-
gdb.COMMAND_DATA,
15-
gdb.COMPLETE_EXPRESSION)
16-
17-
def invoke(self, args, *_):
18-
args = args.split()
19-
# find nonflags
20-
nonflags = []
21-
for i, a in enumerate(args):
22-
if not a.startswith('-'):
23-
nonflags.append(i)
24-
# parse and eval
25-
for i, n in enumerate(nonflags):
26-
try:
27-
args[n] = '%d' % gdb.parse_and_eval(args[n])
28-
except gdb.error as e:
29-
raise gdb.GdbError(e)
30-
31-
# execute
32-
gdb.execute(' '.join(['!./scripts/dbgerr.py'] + args))
33-
34-
DbgErr()
35-
36-
37-
# dbgflags
38-
class DbgFlags(gdb.Command):
39-
"""Decode littlefs flags. See -h/--help for more info."""
40-
41-
def __init__(self):
42-
super().__init__("dbgflags",
43-
gdb.COMMAND_DATA,
44-
gdb.COMPLETE_EXPRESSION)
45-
46-
def invoke(self, args, *_):
47-
args = args.split()
48-
# find nonflags
49-
nonflags = []
50-
for i, a in enumerate(args):
51-
if not a.startswith('-'):
52-
nonflags.append(i)
53-
# parse and eval
54-
for i, n in enumerate(nonflags):
55-
try:
56-
args[n] = '%d' % gdb.parse_and_eval(args[n])
57-
except gdb.error as e:
58-
raise gdb.GdbError(e)
59-
60-
# execute
61-
gdb.execute(' '.join(['!./scripts/dbgflags.py'] + args))
62-
63-
DbgFlags()
64-
65-
66-
# dbgtag
67-
class DbgTag(gdb.Command):
68-
"""Decode littlefs tags. See -h/--help for more info."""
7+
import shlex
8+
9+
10+
# split spaces but only outside of parens and quotes
11+
def gdbsplit(v):
12+
parens = 0
13+
quote = None
14+
escape = False
15+
i_ = 0
16+
for i in range(len(v)):
17+
if v[i].isspace() and not parens and not quote:
18+
v_ = v[i_:i].strip()
19+
if v_:
20+
yield v_
21+
i_ = i+1
22+
elif quote:
23+
if escape:
24+
escape = False
25+
elif v[i] == quote:
26+
quote = None
27+
elif v[i] == '\\':
28+
escape = True
29+
elif v[i] in '\'"':
30+
quote = v[i]
31+
elif v[i] in '([{':
32+
parens += 1
33+
elif v[i] in '}])':
34+
parens -= 1
35+
v_ = v[i_:].strip()
36+
if v_:
37+
yield v_
38+
39+
# common wrapper for dbg scripts
40+
#
41+
# Note some tricks to help interact with bash and gdb:
42+
#
43+
# - Flags are passed as is (-b4096, -t, --trunk)
44+
# - All non-flags are parsed as expressions (file->b.shrub.blocks[0])
45+
# - String expressions may be useful for paths and stuff ("./disk")
46+
#
47+
class DbgCommand(gdb.Command):
48+
"""A littlefs debug script. See -h/--help for more info."""
49+
name = None
50+
path = None
6951

7052
def __init__(self):
71-
super().__init__("dbgtag",
53+
super().__init__(self.name,
7254
gdb.COMMAND_DATA,
7355
gdb.COMPLETE_EXPRESSION)
7456

7557
def invoke(self, args, *_):
76-
args = args.split()
77-
# find nonflags
78-
nonflags = []
79-
for i, a in enumerate(args):
80-
if not a.startswith('-'):
81-
nonflags.append(i)
82-
# parse and eval
83-
for i, n in enumerate(nonflags):
84-
try:
85-
args[n] = '%d' % gdb.parse_and_eval(args[n])
86-
except gdb.error as e:
87-
raise gdb.GdbError(e)
58+
# parse args
59+
args = list(gdbsplit(args))
60+
args_ = []
61+
for a in args:
62+
# pass flags as is
63+
if a.startswith('-'):
64+
args_.append(a)
65+
66+
# parse and eval
67+
else:
68+
try:
69+
v = gdb.parse_and_eval(a)
70+
t = v.type.strip_typedefs()
71+
if t.code in {
72+
gdb.TYPE_CODE_ENUM,
73+
gdb.TYPE_CODE_FLAGS,
74+
gdb.TYPE_CODE_INT,
75+
gdb.TYPE_CODE_RANGE,
76+
gdb.TYPE_CODE_CHAR,
77+
gdb.TYPE_CODE_BOOL}:
78+
v = str(int(v))
79+
elif t.code in {
80+
gdb.TYPE_CODE_FLT}:
81+
v = str(float(v))
82+
else:
83+
try:
84+
v = v.string('utf8')
85+
except gdb.error:
86+
raise gdb.GdbError('Unexpected type: %s' % v.type)
87+
except gdb.error as e:
88+
raise gdb.GdbError(e)
89+
90+
args_.append(shlex.quote(v))
91+
args = args_
8892

8993
# execute
90-
gdb.execute(' '.join(['!./scripts/dbgtag.py'] + args))
94+
gdb.execute(' '.join(['!'+self.path, *args]))
9195

92-
DbgTag()
9396

97+
# at some point this was manual, then I realized I could just glob all
98+
# scripts with this prefix
99+
#
100+
# # dbgerr
101+
# class DbgErr(DbgCommand):
102+
# name = 'dbgerr'
103+
# path = './scripts/dbgerr.py'
104+
#
105+
# # dbgflags
106+
# class DbgFlags(DbgCommand):
107+
# name = 'dbgflags'
108+
# path = './scripts/dbgflags.py'
109+
#
110+
# # dbgtag
111+
# class DbgTag(DbgCommand):
112+
# name = 'dbgtag'
113+
# path = './scripts/dbgtag.py'
114+
115+
import os
116+
import glob
117+
118+
for path in glob.glob(os.path.join(
119+
os.path.dirname(__file__),
120+
'dbg*.py')):
121+
if path == __file__:
122+
continue
123+
124+
# create dbg class
125+
name = os.path.splitext(os.path.basename(path))[0]
126+
type(name, (DbgCommand,), {
127+
'name': name,
128+
'path': path
129+
})
130+
131+
132+
# initialize gdb hooks
133+
for Dbg in DbgCommand.__subclasses__():
134+
if Dbg.__doc__ is None:
135+
Dbg.__doc__ = DbgCommand.__doc__
136+
Dbg()

0 commit comments

Comments
 (0)