Text file src/pkg/runtime/runtime-gdb.py
1 # Copyright 2010 The Go Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style
3 # license that can be found in the LICENSE file.
4
5 """GDB Pretty printers and convenience functions for Go's runtime structures.
6
7 This script is loaded by GDB when it finds a .debug_gdb_scripts
8 section in the compiled binary. The [68]l linkers emit this with a
9 path to this file based on the path to the runtime package.
10 """
11
12 # Known issues:
13 # - pretty printing only works for the 'native' strings. E.g. 'type
14 # foo string' will make foo a plain struct in the eyes of gdb,
15 # circumventing the pretty print triggering.
16
17
18 from __future__ import print_function
19 import re
20 import sys
21
22 print("Loading Go Runtime support.", file=sys.stderr)
23 #http://python3porting.com/differences.html
24 if sys.version > '3':
25 xrange = range
26 # allow to manually reload while developing
27 goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
28 goobjfile.pretty_printers = []
29
30 # G state (runtime2.go)
31
32 def read_runtime_const(varname, default):
33 try:
34 return int(gdb.parse_and_eval(varname))
35 except Exception:
36 return int(default)
37
38
39 G_IDLE = read_runtime_const("'runtime._Gidle'", 0)
40 G_RUNNABLE = read_runtime_const("'runtime._Grunnable'", 1)
41 G_RUNNING = read_runtime_const("'runtime._Grunning'", 2)
42 G_SYSCALL = read_runtime_const("'runtime._Gsyscall'", 3)
43 G_WAITING = read_runtime_const("'runtime._Gwaiting'", 4)
44 G_MORIBUND_UNUSED = read_runtime_const("'runtime._Gmoribund_unused'", 5)
45 G_DEAD = read_runtime_const("'runtime._Gdead'", 6)
46 G_ENQUEUE_UNUSED = read_runtime_const("'runtime._Genqueue_unused'", 7)
47 G_COPYSTACK = read_runtime_const("'runtime._Gcopystack'", 8)
48 G_SCAN = read_runtime_const("'runtime._Gscan'", 0x1000)
49 G_SCANRUNNABLE = G_SCAN+G_RUNNABLE
50 G_SCANRUNNING = G_SCAN+G_RUNNING
51 G_SCANSYSCALL = G_SCAN+G_SYSCALL
52 G_SCANWAITING = G_SCAN+G_WAITING
53
54 sts = {
55 G_IDLE: 'idle',
56 G_RUNNABLE: 'runnable',
57 G_RUNNING: 'running',
58 G_SYSCALL: 'syscall',
59 G_WAITING: 'waiting',
60 G_MORIBUND_UNUSED: 'moribund',
61 G_DEAD: 'dead',
62 G_ENQUEUE_UNUSED: 'enqueue',
63 G_COPYSTACK: 'copystack',
64 G_SCAN: 'scan',
65 G_SCANRUNNABLE: 'runnable+s',
66 G_SCANRUNNING: 'running+s',
67 G_SCANSYSCALL: 'syscall+s',
68 G_SCANWAITING: 'waiting+s',
69 }
70
71
72 #
73 # Value wrappers
74 #
75
76 class SliceValue:
77 "Wrapper for slice values."
78
79 def __init__(self, val):
80 self.val = val
81
82 @property
83 def len(self):
84 return int(self.val['len'])
85
86 @property
87 def cap(self):
88 return int(self.val['cap'])
89
90 def __getitem__(self, i):
91 if i < 0 or i >= self.len:
92 raise IndexError(i)
93 ptr = self.val["array"]
94 return (ptr + i).dereference()
95
96
97 #
98 # Pretty Printers
99 #
100
101
102 class StringTypePrinter:
103 "Pretty print Go strings."
104
105 pattern = re.compile(r'^struct string( \*)?$')
106
107 def __init__(self, val):
108 self.val = val
109
110 def display_hint(self):
111 return 'string'
112
113 def to_string(self):
114 l = int(self.val['len'])
115 return self.val['str'].string("utf-8", "ignore", l)
116
117
118 class SliceTypePrinter:
119 "Pretty print slices."
120
121 pattern = re.compile(r'^struct \[\]')
122
123 def __init__(self, val):
124 self.val = val
125
126 def display_hint(self):
127 return 'array'
128
129 def to_string(self):
130 return str(self.val.type)[6:] # skip 'struct '
131
132 def children(self):
133 sval = SliceValue(self.val)
134 if sval.len > sval.cap:
135 return
136 for idx, item in enumerate(sval):
137 yield ('[{0}]'.format(idx), item)
138
139
140 class MapTypePrinter:
141 """Pretty print map[K]V types.
142
143 Map-typed go variables are really pointers. dereference them in gdb
144 to inspect their contents with this pretty printer.
145 """
146
147 pattern = re.compile(r'^map\[.*\].*$')
148
149 def __init__(self, val):
150 self.val = val
151
152 def display_hint(self):
153 return 'map'
154
155 def to_string(self):
156 return str(self.val.type)
157
158 def children(self):
159 B = self.val['B']
160 buckets = self.val['buckets']
161 oldbuckets = self.val['oldbuckets']
162 flags = self.val['flags']
163 inttype = self.val['hash0'].type
164 cnt = 0
165 for bucket in xrange(2 ** int(B)):
166 bp = buckets + bucket
167 if oldbuckets:
168 oldbucket = bucket & (2 ** (B - 1) - 1)
169 oldbp = oldbuckets + oldbucket
170 oldb = oldbp.dereference()
171 if (oldb['overflow'].cast(inttype) & 1) == 0: # old bucket not evacuated yet
172 if bucket >= 2 ** (B - 1):
173 continue # already did old bucket
174 bp = oldbp
175 while bp:
176 b = bp.dereference()
177 for i in xrange(8):
178 if b['tophash'][i] != 0:
179 k = b['keys'][i]
180 v = b['values'][i]
181 if flags & 1:
182 k = k.dereference()
183 if flags & 2:
184 v = v.dereference()
185 yield str(cnt), k
186 yield str(cnt + 1), v
187 cnt += 2
188 bp = b['overflow']
189
190
191 class ChanTypePrinter:
192 """Pretty print chan[T] types.
193
194 Chan-typed go variables are really pointers. dereference them in gdb
195 to inspect their contents with this pretty printer.
196 """
197
198 pattern = re.compile(r'^struct hchan<.*>$')
199
200 def __init__(self, val):
201 self.val = val
202
203 def display_hint(self):
204 return 'array'
205
206 def to_string(self):
207 return str(self.val.type)
208
209 def children(self):
210 # see chan.c chanbuf(). et is the type stolen from hchan<T>::recvq->first->elem
211 et = [x.type for x in self.val['recvq']['first'].type.target().fields() if x.name == 'elem'][0]
212 ptr = (self.val.address + 1).cast(et.pointer())
213 for i in range(self.val["qcount"]):
214 j = (self.val["recvx"] + i) % self.val["dataqsiz"]
215 yield ('[{0}]'.format(i), (ptr + j).dereference())
216
217
218 #
219 # Register all the *Printer classes above.
220 #
221
222 def makematcher(klass):
223 def matcher(val):
224 try:
225 if klass.pattern.match(str(val.type)):
226 return klass(val)
227 except Exception:
228 pass
229 return matcher
230
231 goobjfile.pretty_printers.extend([makematcher(var) for var in vars().values() if hasattr(var, 'pattern')])
232
233
234 #
235 # Utilities
236 #
237
238 def pc_to_int(pc):
239 # python2 will not cast pc (type void*) to an int cleanly
240 # instead python2 and python3 work with the hex string representation
241 # of the void pointer which we can parse back into an int.
242 # int(pc) will not work.
243 try:
244 # python3 / newer versions of gdb
245 pc = int(pc)
246 except gdb.error:
247 # str(pc) can return things like
248 # "0x429d6c <runtime.gopark+284>", so
249 # chop at first space.
250 pc = int(str(pc).split(None, 1)[0], 16)
251 return pc
252
253
254 #
255 # For reference, this is what we're trying to do:
256 # eface: p *(*(struct 'runtime.rtype'*)'main.e'->type_->data)->string
257 # iface: p *(*(struct 'runtime.rtype'*)'main.s'->tab->Type->data)->string
258 #
259 # interface types can't be recognized by their name, instead we check
260 # if they have the expected fields. Unfortunately the mapping of
261 # fields to python attributes in gdb.py isn't complete: you can't test
262 # for presence other than by trapping.
263
264
265 def is_iface(val):
266 try:
267 return str(val['tab'].type) == "struct runtime.itab *" and str(val['data'].type) == "void *"
268 except gdb.error:
269 pass
270
271
272 def is_eface(val):
273 try:
274 return str(val['_type'].type) == "struct runtime._type *" and str(val['data'].type) == "void *"
275 except gdb.error:
276 pass
277
278
279 def lookup_type(name):
280 try:
281 return gdb.lookup_type(name)
282 except gdb.error:
283 pass
284 try:
285 return gdb.lookup_type('struct ' + name)
286 except gdb.error:
287 pass
288 try:
289 return gdb.lookup_type('struct ' + name[1:]).pointer()
290 except gdb.error:
291 pass
292
293
294 def iface_commontype(obj):
295 if is_iface(obj):
296 go_type_ptr = obj['tab']['_type']
297 elif is_eface(obj):
298 go_type_ptr = obj['_type']
299 else:
300 return
301
302 return go_type_ptr.cast(gdb.lookup_type("struct reflect.rtype").pointer()).dereference()
303
304
305 def iface_dtype(obj):
306 "Decode type of the data field of an eface or iface struct."
307 # known issue: dtype_name decoded from runtime.rtype is "nested.Foo"
308 # but the dwarf table lists it as "full/path/to/nested.Foo"
309
310 dynamic_go_type = iface_commontype(obj)
311 if dynamic_go_type is None:
312 return
313 dtype_name = dynamic_go_type['string'].dereference()['str'].string()
314
315 dynamic_gdb_type = lookup_type(dtype_name)
316 if dynamic_gdb_type is None:
317 return
318
319 type_size = int(dynamic_go_type['size'])
320 uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr
321 if type_size > uintptr_size:
322 dynamic_gdb_type = dynamic_gdb_type.pointer()
323
324 return dynamic_gdb_type
325
326
327 def iface_dtype_name(obj):
328 "Decode type name of the data field of an eface or iface struct."
329
330 dynamic_go_type = iface_commontype(obj)
331 if dynamic_go_type is None:
332 return
333 return dynamic_go_type['string'].dereference()['str'].string()
334
335
336 class IfacePrinter:
337 """Pretty print interface values
338
339 Casts the data field to the appropriate dynamic type."""
340
341 def __init__(self, val):
342 self.val = val
343
344 def display_hint(self):
345 return 'string'
346
347 def to_string(self):
348 if self.val['data'] == 0:
349 return 0x0
350 try:
351 dtype = iface_dtype(self.val)
352 except Exception:
353 return "<bad dynamic type>"
354
355 if dtype is None: # trouble looking up, print something reasonable
356 return "({typename}){data}".format(
357 typename=iface_dtype_name(self.val), data=self.val['data'])
358
359 try:
360 return self.val['data'].cast(dtype).dereference()
361 except Exception:
362 pass
363 return self.val['data'].cast(dtype)
364
365
366 def ifacematcher(val):
367 if is_iface(val) or is_eface(val):
368 return IfacePrinter(val)
369
370 goobjfile.pretty_printers.append(ifacematcher)
371
372 #
373 # Convenience Functions
374 #
375
376
377 class GoLenFunc(gdb.Function):
378 "Length of strings, slices, maps or channels"
379
380 how = ((StringTypePrinter, 'len'), (SliceTypePrinter, 'len'), (MapTypePrinter, 'count'), (ChanTypePrinter, 'qcount'))
381
382 def __init__(self):
383 gdb.Function.__init__(self, "len")
384
385 def invoke(self, obj):
386 typename = str(obj.type)
387 for klass, fld in self.how:
388 if klass.pattern.match(typename):
389 return obj[fld]
390
391
392 class GoCapFunc(gdb.Function):
393 "Capacity of slices or channels"
394
395 how = ((SliceTypePrinter, 'cap'), (ChanTypePrinter, 'dataqsiz'))
396
397 def __init__(self):
398 gdb.Function.__init__(self, "cap")
399
400 def invoke(self, obj):
401 typename = str(obj.type)
402 for klass, fld in self.how:
403 if klass.pattern.match(typename):
404 return obj[fld]
405
406
407 class DTypeFunc(gdb.Function):
408 """Cast Interface values to their dynamic type.
409
410 For non-interface types this behaves as the identity operation.
411 """
412
413 def __init__(self):
414 gdb.Function.__init__(self, "dtype")
415
416 def invoke(self, obj):
417 try:
418 return obj['data'].cast(iface_dtype(obj))
419 except gdb.error:
420 pass
421 return obj
422
423 #
424 # Commands
425 #
426
427 def linked_list(ptr, linkfield):
428 while ptr:
429 yield ptr
430 ptr = ptr[linkfield]
431
432
433 class GoroutinesCmd(gdb.Command):
434 "List all goroutines."
435
436 def __init__(self):
437 gdb.Command.__init__(self, "info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
438
439 def invoke(self, _arg, _from_tty):
440 # args = gdb.string_to_argv(arg)
441 vp = gdb.lookup_type('void').pointer()
442 for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
443 if ptr['atomicstatus'] == G_DEAD:
444 continue
445 s = ' '
446 if ptr['m']:
447 s = '*'
448 pc = ptr['sched']['pc'].cast(vp)
449 pc = pc_to_int(pc)
450 blk = gdb.block_for_pc(pc)
451 status = int(ptr['atomicstatus'])
452 st = sts.get(status, "unknown(%d)" % status)
453 print(s, ptr['goid'], "{0:8s}".format(st), blk.function)
454
455
456 def find_goroutine(goid):
457 """
458 find_goroutine attempts to find the goroutine identified by goid.
459 It returns a tuple of gdb.Value's representing the stack pointer
460 and program counter pointer for the goroutine.
461
462 @param int goid
463
464 @return tuple (gdb.Value, gdb.Value)
465 """
466 vp = gdb.lookup_type('void').pointer()
467 for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
468 if ptr['atomicstatus'] == G_DEAD:
469 continue
470 if ptr['goid'] == goid:
471 break
472 else:
473 return None, None
474 # Get the goroutine's saved state.
475 pc, sp = ptr['sched']['pc'], ptr['sched']['sp']
476 status = ptr['atomicstatus']&~G_SCAN
477 # Goroutine is not running nor in syscall, so use the info in goroutine
478 if status != G_RUNNING and status != G_SYSCALL:
479 return pc.cast(vp), sp.cast(vp)
480
481 # If the goroutine is in a syscall, use syscallpc/sp.
482 pc, sp = ptr['syscallpc'], ptr['syscallsp']
483 if sp != 0:
484 return pc.cast(vp), sp.cast(vp)
485 # Otherwise, the goroutine is running, so it doesn't have
486 # saved scheduler state. Find G's OS thread.
487 m = ptr['m']
488 if m == 0:
489 return None, None
490 for thr in gdb.selected_inferior().threads():
491 if thr.ptid[1] == m['procid']:
492 break
493 else:
494 return None, None
495 # Get scheduler state from the G's OS thread state.
496 curthr = gdb.selected_thread()
497 try:
498 thr.switch()
499 pc = gdb.parse_and_eval('$pc')
500 sp = gdb.parse_and_eval('$sp')
501 finally:
502 curthr.switch()
503 return pc.cast(vp), sp.cast(vp)
504
505
506 class GoroutineCmd(gdb.Command):
507 """Execute gdb command in the context of goroutine <goid>.
508
509 Switch PC and SP to the ones in the goroutine's G structure,
510 execute an arbitrary gdb command, and restore PC and SP.
511
512 Usage: (gdb) goroutine <goid> <gdbcmd>
513
514 You could pass "all" as <goid> to apply <gdbcmd> to all goroutines.
515
516 For example: (gdb) goroutine all <gdbcmd>
517
518 Note that it is ill-defined to modify state in the context of a goroutine.
519 Restrict yourself to inspecting values.
520 """
521
522 def __init__(self):
523 gdb.Command.__init__(self, "goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
524
525 def invoke(self, arg, _from_tty):
526 goid_str, cmd = arg.split(None, 1)
527 goids = []
528
529 if goid_str == 'all':
530 for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
531 goids.append(int(ptr['goid']))
532 else:
533 goids = [int(gdb.parse_and_eval(goid_str))]
534
535 for goid in goids:
536 self.invoke_per_goid(goid, cmd)
537
538 def invoke_per_goid(self, goid, cmd):
539 pc, sp = find_goroutine(goid)
540 if not pc:
541 print("No such goroutine: ", goid)
542 return
543 pc = pc_to_int(pc)
544 save_frame = gdb.selected_frame()
545 gdb.parse_and_eval('$save_sp = $sp')
546 gdb.parse_and_eval('$save_pc = $pc')
547 # In GDB, assignments to sp must be done from the
548 # top-most frame, so select frame 0 first.
549 gdb.execute('select-frame 0')
550 gdb.parse_and_eval('$sp = {0}'.format(str(sp)))
551 gdb.parse_and_eval('$pc = {0}'.format(str(pc)))
552 try:
553 gdb.execute(cmd)
554 finally:
555 # In GDB, assignments to sp must be done from the
556 # top-most frame, so select frame 0 first.
557 gdb.execute('select-frame 0')
558 gdb.parse_and_eval('$pc = $save_pc')
559 gdb.parse_and_eval('$sp = $save_sp')
560 save_frame.select()
561
562
563 class GoIfaceCmd(gdb.Command):
564 "Print Static and dynamic interface types"
565
566 def __init__(self):
567 gdb.Command.__init__(self, "iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
568
569 def invoke(self, arg, _from_tty):
570 for obj in gdb.string_to_argv(arg):
571 try:
572 #TODO fix quoting for qualified variable names
573 obj = gdb.parse_and_eval(str(obj))
574 except Exception as e:
575 print("Can't parse ", obj, ": ", e)
576 continue
577
578 if obj['data'] == 0:
579 dtype = "nil"
580 else:
581 dtype = iface_dtype(obj)
582
583 if dtype is None:
584 print("Not an interface: ", obj.type)
585 continue
586
587 print("{0}: {1}".format(obj.type, dtype))
588
589 # TODO: print interface's methods and dynamic type's func pointers thereof.
590 #rsc: "to find the number of entries in the itab's Fn field look at
591 # itab.inter->numMethods
592 # i am sure i have the names wrong but look at the interface type
593 # and its method count"
594 # so Itype will start with a commontype which has kind = interface
595
596 #
597 # Register all convenience functions and CLI commands
598 #
599 GoLenFunc()
600 GoCapFunc()
601 DTypeFunc()
602 GoroutinesCmd()
603 GoroutineCmd()
604 GoIfaceCmd()
View as plain text