Login
Log in using an SSO provider:
Fedora Account System
Red Hat Associate
Red Hat Customer
Login using a Red Hat Bugzilla account
Forgot Password
Create an Account
Red Hat Bugzilla – Attachment 991759 Details for
Bug 1192721
Fix debugging - fix runtime-gdb.py
Home
New
Search
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh109 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
Migrated Products
[?]
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
Fedora packaging + runtime-gdb.py fix
golang.patch (text/plain), 15.26 KB, created by
Jan Kratochvil
on 2015-02-14 17:20:58 UTC
(
hide
)
Description:
Fedora packaging + runtime-gdb.py fix
Filename:
MIME Type:
Creator:
Jan Kratochvil
Created:
2015-02-14 17:20:58 UTC
Size:
15.26 KB
patch
obsolete
>diff --git a/golang-gdbinit b/golang-gdbinit >index 4ef690b..ecddca6 100644 >--- a/golang-gdbinit >+++ b/golang-gdbinit >@@ -1 +1 @@ >-add-auto-load-safe-path /usr/lib/golang/src/pkg/runtime/runtime-gdb.py >+add-auto-load-safe-path /usr/lib/golang/src/runtime/runtime-gdb.py >diff --git a/golang.spec b/golang.spec >index cdd7e65..141b5e7 100644 >--- a/golang.spec >+++ b/golang.spec >@@ -68,6 +68,8 @@ Patch0: golang-1.2-verbose-build.patch > # https://bugzilla.redhat.com/show_bug.cgi?id=1038683 > Patch1: golang-1.2-remove-ECC-p224.patch > >+Patch2: runtime-gdb.patch >+ > # Having documentation separate was broken > Obsoletes: %{name}-docs < 1.1-4 > >@@ -80,6 +82,7 @@ ExclusiveArch: %{go_arches} > Source100: golang-gdbinit > Source101: golang-prelink.conf > Source102: macros.golang >+Source103: runtime-gdb.py > > %description > %{summary}. >@@ -319,6 +322,10 @@ end > > # remove the P224 curve > %patch1 -p1 >+%patch2 -p1 >+ >+test -e src/runtime/runtime-gdb.py >+cp -pv %{SOURCE103} src/runtime/runtime-gdb.py > > %build > # set up final install location >diff --git a/runtime-gdb.patch b/runtime-gdb.patch >new file mode 100644 >index 0000000..22a8116 >--- /dev/null >+++ b/runtime-gdb.patch >@@ -0,0 +1,20 @@ >+--- go-orig/src/cmd/ld/dwarf.c 2015-02-11 22:44:53.280502027 +0100 >++++ go/src/cmd/ld/dwarf.c 2015-02-11 22:51:42.818381615 +0100 >+@@ -1414,7 +1414,7 @@ movetomodule(DWDie *parent) >+ die->link = parent->child; >+ } >+ >+-// If the pcln table contains runtime/string.goc, use that to set gdbscript path. >++// If the pcln table contains runtime/string.go, use that to set gdbscript path. >+ static void >+ finddebugruntimepath(LSym *s) >+ { >+@@ -1427,7 +1427,7 @@ finddebugruntimepath(LSym *s) >+ >+ for(i=0; i<s->pcln->nfile; i++) { >+ f = s->pcln->file[i]; >+- if((p = strstr(f->name, "runtime/string.goc")) != nil) { >++ if((p = strstr(f->name, "runtime/string.go")) != nil) { >+ *p = '\0'; >+ snprint(gdbscript, sizeof gdbscript, "%sruntime/runtime-gdb.py", f->name); >+ *p = 'r'; >diff --git a/runtime-gdb.py b/runtime-gdb.py >new file mode 100644 >index 0000000..08a3b80 >--- /dev/null >+++ b/runtime-gdb.py >@@ -0,0 +1,495 @@ >+# Copyright 2010 The Go Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style >+# license that can be found in the LICENSE file. >+ >+"""GDB Pretty printers and convenience functions for Go's runtime structures. >+ >+This script is loaded by GDB when it finds a .debug_gdb_scripts >+section in the compiled binary. The [68]l linkers emit this with a >+path to this file based on the path to the runtime package. >+""" >+ >+# Known issues: >+# - pretty printing only works for the 'native' strings. E.g. 'type >+# foo string' will make foo a plain struct in the eyes of gdb, >+# circumventing the pretty print triggering. >+ >+ >+from __future__ import print_function >+import re >+import sys >+ >+print("Loading Go Runtime support.", file=sys.stderr) >+#http://python3porting.com/differences.html >+if sys.version > '3': >+ xrange = range >+# allow to manually reload while developing >+goobjfile = gdb.current_objfile() or gdb.objfiles()[0] >+goobjfile.pretty_printers = [] >+ >+# >+# Pretty Printers >+# >+ >+ >+class StringTypePrinter: >+ "Pretty print Go strings." >+ >+ pattern = re.compile(r'^struct string$') >+ >+ def __init__(self, val): >+ self.val = val >+ >+ def display_hint(self): >+ return 'string' >+ >+ def to_string(self): >+ l = int(self.val['len']) >+ return self.val['str'].string("utf-8", "ignore", l) >+ >+ >+class SliceTypePrinter: >+ "Pretty print slices." >+ >+ pattern = re.compile(r'^struct \[\]') >+ >+ def __init__(self, val): >+ self.val = val >+ >+ def display_hint(self): >+ return 'array' >+ >+ def to_string(self): >+ return str(self.val.type)[6:] # skip 'struct ' >+ >+ def children(self): >+ if self.val["len"] > self.val["cap"]: >+ return >+ ptr = self.val["array"] >+ for idx in range(int(self.val["len"])): >+ yield ('[{0}]'.format(idx), (ptr + idx).dereference()) >+ >+ >+class MapTypePrinter: >+ """Pretty print map[K]V types. >+ >+ Map-typed go variables are really pointers. dereference them in gdb >+ to inspect their contents with this pretty printer. >+ """ >+ >+ pattern = re.compile(r'^map\[.*\].*$') >+ >+ def __init__(self, val): >+ self.val = val >+ >+ def display_hint(self): >+ return 'map' >+ >+ def to_string(self): >+ return str(self.val.type) >+ >+ def children(self): >+ B = self.val['b'] >+ buckets = self.val['buckets'] >+ oldbuckets = self.val['oldbuckets'] >+ flags = self.val['flags'] >+ inttype = self.val['hash0'].type >+ cnt = 0 >+ for bucket in xrange(2 ** int(B)): >+ bp = buckets + bucket >+ if oldbuckets: >+ oldbucket = bucket & (2 ** (B - 1) - 1) >+ oldbp = oldbuckets + oldbucket >+ oldb = oldbp.dereference() >+ if (oldb['overflow'].cast(inttype) & 1) == 0: # old bucket not evacuated yet >+ if bucket >= 2 ** (B - 1): >+ continue # already did old bucket >+ bp = oldbp >+ while bp: >+ b = bp.dereference() >+ for i in xrange(8): >+ if b['tophash'][i] != 0: >+ k = b['keys'][i] >+ v = b['values'][i] >+ if flags & 1: >+ k = k.dereference() >+ if flags & 2: >+ v = v.dereference() >+ yield str(cnt), k >+ yield str(cnt + 1), v >+ cnt += 2 >+ bp = b['overflow'] >+ >+ >+class ChanTypePrinter: >+ """Pretty print chan[T] types. >+ >+ Chan-typed go variables are really pointers. dereference them in gdb >+ to inspect their contents with this pretty printer. >+ """ >+ >+ pattern = re.compile(r'^struct hchan<.*>$') >+ >+ def __init__(self, val): >+ self.val = val >+ >+ def display_hint(self): >+ return 'array' >+ >+ def to_string(self): >+ return str(self.val.type) >+ >+ def children(self): >+ # see chan.c chanbuf(). et is the type stolen from hchan<T>::recvq->first->elem >+ et = [x.type for x in self.val['recvq']['first'].type.target().fields() if x.name == 'elem'][0] >+ ptr = (self.val.address + 1).cast(et.pointer()) >+ for i in range(self.val["qcount"]): >+ j = (self.val["recvx"] + i) % self.val["dataqsiz"] >+ yield ('[{0}]'.format(i), (ptr + j).dereference()) >+ >+ >+# >+# Register all the *Printer classes above. >+# >+ >+def makematcher(klass): >+ def matcher(val): >+ try: >+ if klass.pattern.match(str(val.type)): >+ return klass(val) >+ except Exception: >+ pass >+ return matcher >+ >+goobjfile.pretty_printers.extend([makematcher(var) for var in vars().values() if hasattr(var, 'pattern')]) >+ >+# >+# For reference, this is what we're trying to do: >+# eface: p *(*(struct 'runtime.rtype'*)'main.e'->type_->data)->string >+# iface: p *(*(struct 'runtime.rtype'*)'main.s'->tab->Type->data)->string >+# >+# interface types can't be recognized by their name, instead we check >+# if they have the expected fields. Unfortunately the mapping of >+# fields to python attributes in gdb.py isn't complete: you can't test >+# for presence other than by trapping. >+ >+ >+def is_iface(val): >+ try: >+ return str(val['tab'].type) == "struct runtime.itab *" and str(val['data'].type) == "void *" >+ except gdb.error: >+ pass >+ >+ >+def is_eface(val): >+ try: >+ return str(val['_type'].type) == "struct runtime._type *" and str(val['data'].type) == "void *" >+ except gdb.error: >+ pass >+ >+ >+def lookup_type(name): >+ try: >+ return gdb.lookup_type(name) >+ except gdb.error: >+ pass >+ try: >+ return gdb.lookup_type('struct ' + name) >+ except gdb.error: >+ pass >+ try: >+ return gdb.lookup_type('struct ' + name[1:]).pointer() >+ except gdb.error: >+ pass >+ >+# FIXME: >+#_rctp_type = gdb.lookup_type("struct runtime.rtype").pointer() >+ >+ >+def iface_commontype(obj): >+ if is_iface(obj): >+ go_type_ptr = obj['tab']['_type'] >+ elif is_eface(obj): >+ go_type_ptr = obj['_type'] >+ else: >+ return >+ >+# FIXME: >+ return >+# return go_type_ptr.cast(_rctp_type).dereference() >+ >+ >+def iface_dtype(obj): >+ "Decode type of the data field of an eface or iface struct." >+ # known issue: dtype_name decoded from runtime.rtype is "nested.Foo" >+ # but the dwarf table lists it as "full/path/to/nested.Foo" >+ >+ dynamic_go_type = iface_commontype(obj) >+ if dynamic_go_type is None: >+ return >+ dtype_name = dynamic_go_type['string'].dereference()['str'].string() >+ >+ dynamic_gdb_type = lookup_type(dtype_name) >+ if dynamic_gdb_type is None: >+ return >+ >+ type_size = int(dynamic_go_type['size']) >+ uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr >+ if type_size > uintptr_size: >+ dynamic_gdb_type = dynamic_gdb_type.pointer() >+ >+ return dynamic_gdb_type >+ >+ >+def iface_dtype_name(obj): >+ "Decode type name of the data field of an eface or iface struct." >+ >+ dynamic_go_type = iface_commontype(obj) >+ if dynamic_go_type is None: >+ return >+ return dynamic_go_type['string'].dereference()['str'].string() >+ >+ >+class IfacePrinter: >+ """Pretty print interface values >+ >+ Casts the data field to the appropriate dynamic type.""" >+ >+ def __init__(self, val): >+ self.val = val >+ >+ def display_hint(self): >+ return 'string' >+ >+ def to_string(self): >+ if self.val['data'] == 0: >+ return 0x0 >+ try: >+ dtype = iface_dtype(self.val) >+ except Exception: >+ return "<bad dynamic type>" >+ >+ if dtype is None: # trouble looking up, print something reasonable >+ return "({0}){0}".format(iface_dtype_name(self.val), self.val['data']) >+ >+ try: >+ return self.val['data'].cast(dtype).dereference() >+ except Exception: >+ pass >+ return self.val['data'].cast(dtype) >+ >+ >+def ifacematcher(val): >+ if is_iface(val) or is_eface(val): >+ return IfacePrinter(val) >+ >+goobjfile.pretty_printers.append(ifacematcher) >+ >+# >+# Convenience Functions >+# >+ >+ >+class GoLenFunc(gdb.Function): >+ "Length of strings, slices, maps or channels" >+ >+ how = ((StringTypePrinter, 'len'), (SliceTypePrinter, 'len'), (MapTypePrinter, 'count'), (ChanTypePrinter, 'qcount')) >+ >+ def __init__(self): >+ gdb.Function.__init__(self, "len") >+ >+ def invoke(self, obj): >+ typename = str(obj.type) >+ for klass, fld in self.how: >+ if klass.pattern.match(typename): >+ return obj[fld] >+ >+ >+class GoCapFunc(gdb.Function): >+ "Capacity of slices or channels" >+ >+ how = ((SliceTypePrinter, 'cap'), (ChanTypePrinter, 'dataqsiz')) >+ >+ def __init__(self): >+ gdb.Function.__init__(self, "cap") >+ >+ def invoke(self, obj): >+ typename = str(obj.type) >+ for klass, fld in self.how: >+ if klass.pattern.match(typename): >+ return obj[fld] >+ >+ >+class DTypeFunc(gdb.Function): >+ """Cast Interface values to their dynamic type. >+ >+ For non-interface types this behaves as the identity operation. >+ """ >+ >+ def __init__(self): >+ gdb.Function.__init__(self, "dtype") >+ >+ def invoke(self, obj): >+ try: >+ return obj['data'].cast(iface_dtype(obj)) >+ except gdb.error: >+ pass >+ return obj >+ >+# >+# Commands >+# >+ >+sts = ('idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery') >+ >+ >+def linked_list(ptr, linkfield): >+ while ptr: >+ yield ptr >+ ptr = ptr[linkfield] >+ >+# http://blog.securitymouse.com/2014/10/golang-debugging-turning-pennies-into-gs.html >+ >+class GoroutinesCmd(gdb.Command): >+ "List all goroutines." >+ >+ def __init__(self): >+ gdb.Command.__init__(self, "info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE) >+ >+ def invoke(self, _arg, _from_tty): >+ for allgidx in range(int(gdb.parse_and_eval("'runtime.allglen'"))): >+ allgbase = "'runtime.allg'[%d]" % allgidx >+ >+ st = int(gdb.parse_and_eval(allgbase + ".atomicstatus")) >+ w = gdb.parse_and_eval(allgbase + ".waitreason") >+ #if st == 6: # 'Gdead' # No symbol "Gdead" in current context. >+ #print("skipping over dead goroutine") >+ #continue >+ >+ s = ' ' >+ # "0x55b340 <runtime.m0>" cannot be cast by int(...). >+ m = int(gdb.parse_and_eval("uintptr(" + allgbase + ".m)")) >+ if m: >+ s = '*' >+ >+ # if the status isn't "waiting" then the waitreason doesn' tmatter >+ if st != 4: # 'Gwaiting' # No symbol "Gwaiting" in current context. >+ w = '' >+ w2 = w.split('"') >+ if len(w2) > 1: >+ w = """waitreason="{0}\"""".format(w2[len(w2) - 2]) >+ >+ pc = int(gdb.parse_and_eval(allgbase + ".sched.pc")) >+ blk = gdb.block_for_pc(pc) >+ goid = int(gdb.parse_and_eval(allgbase + ".goid")) >+ a = "fname={0} faddr={1}".format(blk.function, hex(pc)) >+ >+ print(s, goid, "{0:8s}".format(sts[st]), a, "&g={0}".format(gdb.parse_and_eval(allgbase)), w) >+ >+def find_goroutine(goid): >+ """ >+ find_goroutine attempts to find the goroutine identified by goid. >+ It returns a touple of gdv.Value's representing the stack pointer >+ and program counter pointer for the goroutine. >+ >+ @param int goid >+ >+ @return tuple (gdb.Value, gdb.Value) >+ """ >+ vp = gdb.lookup_type('void').pointer() >+ for allgidx in range(int(gdb.parse_and_eval("'runtime.allglen'"))): >+ allgbase = "'runtime.allg'[%d]" % allgidx >+ >+ st = int(gdb.parse_and_eval(allgbase + ".atomicstatus")) >+ if st == 6: # 'Gdead' # No symbol "Gdead" in current context. >+ continue >+ goid_found = int(gdb.parse_and_eval(allgbase + ".goid")) >+ if goid_found == goid: >+ pc = int(gdb.parse_and_eval(allgbase + ".sched.pc")) >+ sp = int(gdb.parse_and_eval(allgbase + ".sched.sp")) >+ return pc, sp >+ return None, None >+ >+ >+class GoroutineCmd(gdb.Command): >+ """Execute gdb command in the context of goroutine <goid>. >+ >+ Switch PC and SP to the ones in the goroutine's G structure, >+ execute an arbitrary gdb command, and restore PC and SP. >+ >+ Usage: (gdb) goroutine <goid> <gdbcmd> >+ >+ Note that it is ill-defined to modify state in the context of a goroutine. >+ Restrict yourself to inspecting values. >+ """ >+ >+ def __init__(self): >+ gdb.Command.__init__(self, "goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE) >+ >+ def invoke(self, arg, _from_tty): >+ goid, cmd = arg.split(None, 1) >+ goid = gdb.parse_and_eval(goid) >+ pc, sp = find_goroutine(int(goid)) >+ if not pc: >+ print("No such goroutine: ", goid) >+ return >+ try: >+ #python3 / newer versions of gdb >+ pc = int(pc) >+ except gdb.error: >+ pc = int(str(pc), 16) >+ save_frame = gdb.selected_frame() >+ gdb.parse_and_eval('$save_pc = $pc') >+ gdb.parse_and_eval('$save_sp = $sp') >+ gdb.parse_and_eval('$pc = {0}'.format(str(pc))) >+ gdb.parse_and_eval('$sp = {0}'.format(str(sp))) >+ try: >+ gdb.execute(cmd) >+ finally: >+ gdb.parse_and_eval('$pc = $save_pc') >+ gdb.parse_and_eval('$sp = $save_sp') >+ save_frame.select() >+ >+ >+class GoIfaceCmd(gdb.Command): >+ "Print Static and dynamic interface types" >+ >+ def __init__(self): >+ gdb.Command.__init__(self, "iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL) >+ >+ def invoke(self, arg, _from_tty): >+ for obj in gdb.string_to_argv(arg): >+ try: >+ #TODO fix quoting for qualified variable names >+ obj = gdb.parse_and_eval(str(obj)) >+ except Exception as e: >+ print("Can't parse ", obj, ": ", e) >+ continue >+ >+ if obj['data'] == 0: >+ dtype = "nil" >+ else: >+ dtype = iface_dtype(obj) >+ >+ if dtype is None: >+ print("Not an interface: ", obj.type) >+ continue >+ >+ print("{0}: {1}".format(obj.type, dtype)) >+ >+# TODO: print interface's methods and dynamic type's func pointers thereof. >+#rsc: "to find the number of entries in the itab's Fn field look at >+# itab.inter->numMethods >+# i am sure i have the names wrong but look at the interface type >+# and its method count" >+# so Itype will start with a commontype which has kind = interface >+ >+# >+# Register all convenience functions and CLI commands >+# >+GoLenFunc() >+GoCapFunc() >+DTypeFunc() >+GoroutinesCmd() >+GoroutineCmd() >+GoIfaceCmd()
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1192721
:
991759
|
991771
|
994184