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