]>
Commit | Line | Data |
---|---|---|
5b4483f1 MF |
1 | #!/usr/bin/python3 |
2 | ||
3 | import inspect | |
4 | import os | |
5 | from pathlib import Path | |
6 | import sys | |
7 | ||
8 | import gdb | |
9 | ||
10 | ||
11 | # | |
12 | # Load frameworks if available. | |
13 | # | |
14 | ||
15 | if False: | |
16 | PWNDBG = Path('/usr/local/src/pwndbg/gdbinit.py') | |
17 | GDB_DASHBOARD = Path('/usr/local/src/gdb-dashboard/.gdbinit') | |
18 | if PWNDBG.exists(): | |
19 | gdb.execute(f'source {PWNDBG}') | |
20 | elif GDB_DASHBOARD.exists(): | |
21 | gdb.execute(f'source {GDB_DASHBOARD}') | |
22 | ||
23 | ||
24 | # | |
25 | # Random helpers. | |
26 | # | |
27 | ||
28 | TRACE = False | |
29 | ||
30 | class VapierCommand(gdb.Command): | |
31 | """Base class for my custom commands.""" | |
32 | ||
33 | CMD_INIT = () | |
34 | CATCH_INVOKE_ERROR = True | |
35 | ||
36 | def __init__(self): | |
37 | gdb.Command.__init__(self, *self.CMD_INIT) | |
38 | ||
39 | def invoke(self, arg, from_tty): | |
40 | try: | |
41 | if hasattr(self, 'v_invoke_argv'): | |
42 | argv = gdb.string_to_argv(arg) | |
43 | self.v_invoke_argv(argv, from_tty) | |
44 | else: | |
45 | self.v_invoke(arg, from_tty) | |
46 | except gdb.error as e: | |
47 | if self.CATCH_INVOKE_ERROR: | |
48 | print(e, file=sys.stderr) | |
49 | else: | |
50 | raise | |
51 | ||
52 | def v_exec(self, cmd): | |
53 | if TRACE: | |
54 | print(f'+ {cmd}') | |
55 | gdb.execute(cmd) | |
56 | ||
57 | def v_parse_int(self, arg): | |
58 | try: | |
59 | return int(arg) | |
60 | except ValueError: | |
61 | pass | |
62 | ||
63 | try: | |
64 | return int(arg, 16) | |
65 | except ValueError as e: | |
66 | raise gdb.error(f'Not a decimal or hex integer: {arg}') | |
67 | ||
68 | ||
69 | class VapierTraceCommand(VapierCommand): | |
70 | """Toggle tracing of helpers.""" | |
71 | ||
72 | CMD_INIT = ('vapier-trace', gdb.COMMAND_SUPPORT) | |
73 | ||
74 | def v_invoke(self, arg, from_tty): | |
75 | global TRACE | |
76 | if arg: | |
77 | TRACE = bool(arg) | |
78 | else: | |
79 | TRACE = not TRACE | |
80 | print(f'Tracing of vapier helpers is now {"on" if TRACE else "off"}') | |
81 | ||
82 | ||
83 | class ExitCommand(VapierCommand): | |
84 | """Exit gdb. | |
85 | Alias to 'quit'.\ | |
86 | """ | |
87 | CMD_INIT = ('exit', gdb.COMMAND_SUPPORT) | |
88 | ||
89 | def v_invoke(self, arg, from_tty): | |
90 | self.dont_repeat() | |
91 | self.v_exec(f'quit {arg}') | |
92 | ||
93 | ||
94 | class LoadBlackfinCommands(VapierCommand): | |
95 | """Load Blackfin specific commands.""" | |
96 | ||
97 | BFIN_CONFIG = Path('~/.gdbinit.bfin').expanduser() | |
98 | CMD_INIT = ('blackfin-commands', gdb.COMMAND_SUPPORT) | |
99 | ||
100 | def v_invoke(self, arg, from_tty): | |
101 | self.dont_repeat() | |
102 | self.v_exec(f'source {self.BFIN_CONFIG}') | |
103 | ||
104 | ||
105 | class GoCommand(VapierCommand): | |
106 | """A simple goto-like helper. | |
107 | Basically an alias to 'jump *<addr>'.\ | |
108 | """ | |
109 | ||
110 | CMD_INIT = ('go', gdb.COMMAND_RUNNING) | |
111 | ||
112 | def v_invoke(self, arg, from_tty): | |
113 | self.v_exec(f'jump *{arg}') | |
114 | ||
115 | ||
116 | class DiCommand(VapierCommand): | |
117 | ||
118 | CMD_INIT = ('di', gdb.COMMAND_DATA) | |
119 | ||
120 | def v_invoke_argv(self, argv, from_tty): | |
121 | self.dont_repeat() | |
122 | if not argv: | |
123 | base = '$pc' | |
124 | elif len(argv) == 1: | |
125 | base = argv[0] | |
126 | else: | |
127 | raise gdb.error('di takes 0 or 1 arguments') | |
128 | self.v_exec(f'disassemble {base} ({base} + 0x40)') | |
129 | ||
130 | ||
131 | class DisCommand(VapierCommand): | |
132 | ||
133 | CMD_INIT = ('dis', gdb.COMMAND_DATA) | |
134 | ||
135 | def v_invoke_argv(self, argv, from_tty): | |
136 | self.dont_repeat() | |
137 | if not argv: | |
138 | base = '$pc' | |
139 | elif len(argv) == 1: | |
140 | base = argv[0] | |
141 | else: | |
142 | raise gdb.error('dis takes 0 or 1 arguments') | |
143 | self.v_exec(f'disassemble {base},+0x40') | |
144 | ||
145 | ||
146 | class UBootMdCommand(VapierCommand): | |
147 | """Display memory. | |
148 | Usage: md <unit type> <address> [count=64] | |
149 | Display [count] <unit type> starting at <address>.\ | |
150 | """ | |
151 | ||
152 | CMD_INIT = ('md', gdb.COMMAND_DATA) | |
153 | ||
154 | def v_invoke_argv(self, argv, from_tty): | |
155 | self.dont_repeat() | |
156 | if len(argv) == 2: | |
157 | count = 64 | |
158 | unit, addr = argv | |
159 | elif len(argv) == 3: | |
160 | unit, addr, count = argv | |
161 | else: | |
162 | raise gdb.error('usage: <unit> <addr> [count]') | |
163 | self.v_exec(f'x/{count}x{unit} {addr}') | |
164 | ||
165 | ||
166 | class UBootMemoryDisplayCommand(VapierCommand): | |
167 | """Display memory. | |
168 | Usage: md[cbwlq] <address> [count=64] | |
169 | Display [count] <chars|bytes|words|longs|quads> starting at <address>.\ | |
170 | """ | |
171 | ||
172 | UNIT = None | |
173 | RADIX = 16 | |
174 | ||
175 | def v_invoke_argv(self, argv, from_tty): | |
176 | assert self.UNIT | |
177 | self.dont_repeat() | |
178 | ||
179 | if len(argv) == 1: | |
180 | count = 64 | |
181 | addr, = argv | |
182 | elif len(argv) == 2: | |
183 | addr, count = argv | |
184 | else: | |
185 | raise gdb.error('usage: <addr> [count]') | |
186 | ||
187 | if self.RADIX != 16: | |
188 | self.v_exec(f'set output-radix {self.RADIX}') | |
189 | self.v_exec(f'md {self.UNIT} {addr} {count}') | |
190 | if self.RADIX != 16: | |
191 | self.v_exec(f'set output-radix 16') | |
192 | ||
193 | class UBootMdb(UBootMemoryDisplayCommand): | |
194 | __doc__ = UBootMemoryDisplayCommand.__doc__ | |
195 | CMD_INIT = ('mdb', gdb.COMMAND_DATA) | |
196 | UNIT = 'b' | |
197 | ||
198 | class UBootMdw(UBootMemoryDisplayCommand): | |
199 | __doc__ = UBootMemoryDisplayCommand.__doc__ | |
200 | CMD_INIT = ('mdw', gdb.COMMAND_DATA) | |
201 | UNIT = 'h' | |
202 | ||
203 | class UBootMdl(UBootMemoryDisplayCommand): | |
204 | __doc__ = UBootMemoryDisplayCommand.__doc__ | |
205 | CMD_INIT = ('mdl', gdb.COMMAND_DATA) | |
206 | UNIT = 'w' | |
207 | ||
208 | class UBootMdq(UBootMemoryDisplayCommand): | |
209 | __doc__ = UBootMemoryDisplayCommand.__doc__ | |
210 | CMD_INIT = ('mdq', gdb.COMMAND_DATA) | |
211 | UNIT = 'g' | |
212 | ||
213 | class UBootMdc(UBootMemoryDisplayCommand): | |
214 | __doc__ = UBootMemoryDisplayCommand.__doc__ | |
215 | CMD_INIT = ('mdc', gdb.COMMAND_DATA) | |
216 | UNIT = 'c' | |
217 | RADIX = 10 | |
218 | ||
219 | ||
220 | class UBootMemoryWriteCommand(VapierCommand): | |
221 | """Write memory. | |
222 | Usage: mw[bwlq] <address> <value> <count> | |
223 | Set <count> <bytes|words|longs|quads> at <address> to <value>.\ | |
224 | """ | |
225 | ||
226 | UNIT = None | |
227 | ||
228 | def v_invoke_argv(self, argv, from_tty): | |
229 | assert self.UNIT | |
230 | self.dont_repeat() | |
231 | ||
232 | if len(argv) == 3: | |
233 | addr, val, count = argv | |
234 | else: | |
235 | raise gdb.error('usage: <addr> <val> <count>') | |
236 | count = self.v_parse_int(count) | |
237 | ||
238 | offset = 0 | |
239 | while count > 0: | |
240 | self.v_exec(f'set *(({self.UNIT}*){addr} + {offset}) = {val}') | |
241 | offset += 1 | |
242 | count -= 1 | |
243 | ||
244 | class UBootMwb(UBootMemoryWriteCommand): | |
245 | __doc__ = UBootMemoryWriteCommand.__doc__ | |
246 | CMD_INIT = ('mwb', gdb.COMMAND_DATA) | |
247 | UNIT = 'unsigned char' | |
248 | ||
249 | class UBootMww(UBootMemoryWriteCommand): | |
250 | __doc__ = UBootMemoryWriteCommand.__doc__ | |
251 | CMD_INIT = ('mww', gdb.COMMAND_DATA) | |
252 | UNIT = 'unsigned short' | |
253 | ||
254 | class UBootMwl(UBootMemoryWriteCommand): | |
255 | __doc__ = UBootMemoryWriteCommand.__doc__ | |
256 | CMD_INIT = ('mwl', gdb.COMMAND_DATA) | |
257 | UNIT = 'unsigned int' | |
258 | ||
259 | class UBootMwq(UBootMemoryWriteCommand): | |
260 | __doc__ = UBootMemoryWriteCommand.__doc__ | |
261 | CMD_INIT = ('mwq', gdb.COMMAND_DATA) | |
262 | UNIT = 'unsigned long long' | |
263 | ||
264 | ||
265 | #class UBootCompareCommand(VapierCommand): | |
266 | # """Compare memory regions. | |
267 | #Usage: cmp[bwlq] <address> <address> <count> | |
268 | #Compare <count> <bytes|words|longs|quads> between <address> and <address>.\ | |
269 | #""" | |
270 | # | |
271 | # UNIT = None | |
272 | # | |
273 | # def v_invoke_argv(self, argv, from_tty): | |
274 | # assert self.UNIT | |
275 | # self.dont_repeat() | |
276 | # | |
277 | # if len(argv) == 3: | |
278 | # addr1, addr2, count = argv | |
279 | # else: | |
280 | # raise gdb.error('usage: <addr1> <addr2> <count>') | |
281 | # count = self.v_parse_int(count) | |
282 | # | |
283 | # set $$addr1 = $arg0 | |
284 | # set $$addr2 = $arg1 | |
285 | # set $$count = $arg2 | |
286 | # while $$count-- > 0 | |
287 | # if (*$$addr1 != *$$addr2) | |
288 | # printf "Data mismatch at %#x units (@%#x != @%#x)\n", $arg2, $$addr1, $$addr2 | |
289 | # set $$count = -100 | |
290 | # end | |
291 | # set $$addr1 += 1 | |
292 | # set $$addr2 += 1 | |
293 | # end | |
294 | # if $$count == -1 | |
295 | # printf "Data matches for %#x units\n", $arg2 | |
296 | # end | |
297 | # | |
298 | #class UBootCmpb(UBootCompareCommand): | |
299 | # __doc__ = UBootCompareCommand.__doc__ | |
300 | # CMD_INIT = ('cmpb', gdb.COMMAND_DATA) | |
301 | # UNIT = 'unsigned char' | |
302 | # | |
303 | #class UBootCmpw(UBootCompareCommand): | |
304 | # __doc__ = UBootCompareCommand.__doc__ | |
305 | # CMD_INIT = ('cmpw', gdb.COMMAND_DATA) | |
306 | # UNIT = 'unsigned short' | |
307 | # | |
308 | #class UBootCmpl(UBootCompareCommand): | |
309 | # __doc__ = UBootCompareCommand.__doc__ | |
310 | # CMD_INIT = ('cmpl', gdb.COMMAND_DATA) | |
311 | # UNIT = 'unsigned int' | |
312 | # | |
313 | #class UBootCmpq(UBootCompareCommand): | |
314 | # __doc__ = UBootCompareCommand.__doc__ | |
315 | # CMD_INIT = ('cmpq', gdb.COMMAND_DATA) | |
316 | # UNIT = 'unsigned long long' | |
317 | # | |
318 | # | |
319 | #class UBootCopyCommand(VapierCommand): | |
320 | # """Copy memory regions. | |
321 | #Usage: cp[bwlq] <src> <dst> <count> | |
322 | #Copy <count> <bytes|words|longs|quads> from <src> to <dst>.\ | |
323 | #""" | |
324 | # | |
325 | # UNIT = None | |
326 | # | |
327 | # def v_invoke_argv(self, argv, from_tty): | |
328 | # assert self.UNIT | |
329 | # self.dont_repeat() | |
330 | # | |
331 | # if len(argv) == 3: | |
332 | # src, dst, count = argv | |
333 | # else: | |
334 | # raise gdb.error('usage: <addr1> <addr2> <count>') | |
335 | # count = self.v_parse_int(count) | |
336 | # | |
337 | # offset = 0 | |
338 | # while count > 0: | |
339 | # self.v_exec(f'set *(({self.UNIT}*){addr} + {offset}) = {val}') | |
340 | # count -= 1 | |
341 | # offset += 1 | |
342 | # set *$$dst = *$$src | |
343 | # set $$src += 1 | |
344 | # set $$dst += 1 | |
345 | # print(f'Copied {argv[2]} units from {addr1} to {addr2}') | |
346 | # | |
347 | #class UBootCpb(UBootCopyCommand): | |
348 | # __doc__ = UBootCopyCommand.__doc__ | |
349 | # CMD_INIT = ('cpb', gdb.COMMAND_DATA) | |
350 | # UNIT = 'unsigned char' | |
351 | # | |
352 | #class UBootCpw(UBootCopyCommand): | |
353 | # __doc__ = UBootCopyCommand.__doc__ | |
354 | # CMD_INIT = ('cpw', gdb.COMMAND_DATA) | |
355 | # UNIT = 'unsigned short' | |
356 | # | |
357 | #class UBootCpl(UBootCopyCommand): | |
358 | # __doc__ = UBootCopyCommand.__doc__ | |
359 | # CMD_INIT = ('cpl', gdb.COMMAND_DATA) | |
360 | # UNIT = 'unsigned int' | |
361 | # | |
362 | #class UBootCpq(UBootCopyCommand): | |
363 | # __doc__ = UBootCopyCommand.__doc__ | |
364 | # CMD_INIT = ('cpq', gdb.COMMAND_DATA) | |
365 | # UNIT = 'unsigned long long' | |
366 | ||
367 | ||
368 | # Probe & load all commands registered. | |
369 | for cls in list(globals().values()): | |
370 | if (inspect.isclass(cls) and | |
371 | issubclass(cls, VapierCommand) and | |
372 | cls.CMD_INIT): | |
373 | cls() |