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