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