forked from qt-creator/qt-creator
This is an attempt to make it work with released gdb 7.0. It uses some ugly workarounds to compensate for the missing gdb.Block and gdb.Symbol structures.
858 lines
28 KiB
Python
858 lines
28 KiB
Python
|
|
#Note: Keep name-type-value-numchild-extra order
|
|
|
|
#return
|
|
|
|
import sys
|
|
import traceback
|
|
import gdb
|
|
import base64
|
|
import curses.ascii
|
|
|
|
# only needed for gdb 7.0
|
|
import os
|
|
import tempfile
|
|
|
|
verbosity = 0
|
|
verbosity = 1
|
|
|
|
def select(condition, if_expr, else_expr):
|
|
if condition:
|
|
return if_expr
|
|
return else_expr
|
|
|
|
def qmin(n, m):
|
|
if n < m:
|
|
return n
|
|
return m
|
|
|
|
def parseAndEvaluate(exp):
|
|
if gdb.VERSION.startswith("6.8.50.2009"):
|
|
return gdb.parse_and_eval(exp)
|
|
# Work around non-existing gdb.parse_and_eval as in released 7.0
|
|
gdb.execute("set logging redirect on")
|
|
gdb.execute("set logging on")
|
|
gdb.execute("print %s" % exp)
|
|
gdb.execute("set logging off")
|
|
return gdb.history(0)
|
|
|
|
def listOfLocals():
|
|
try:
|
|
frame = gdb.selected_frame()
|
|
#warn("FRAME %s: " % frame)
|
|
except RuntimeError:
|
|
return ""
|
|
|
|
items = []
|
|
if gdb.VERSION.startswith("6.8.50.2009"):
|
|
# archer-tromey-python
|
|
block = frame.block()
|
|
while True:
|
|
if block is None:
|
|
warn("UNEXPECTED 'None' BLOCK")
|
|
break
|
|
for symbol in block:
|
|
name = symbol.print_name
|
|
|
|
if name == "__in_chrg":
|
|
continue
|
|
|
|
# "NotImplementedError: Symbol type not yet supported in
|
|
# Python scripts."
|
|
#warn("SYMBOL %s: " % symbol.value)
|
|
#warn("SYMBOL %s (%s): " % (symbol, name))
|
|
item = Item(0, "local", name, name)
|
|
try:
|
|
item.value = frame.read_var(name) # this is a gdb value
|
|
except RuntimeError:
|
|
# happens for void foo() { std::string s; std::wstring w; }
|
|
#warn(" FRAME READ VAR ERROR: %s (%s): " % (symbol, name))
|
|
continue
|
|
#warn("ITEM %s: " % item.value)
|
|
items.append(item)
|
|
# The outermost block in a function has the function member
|
|
# FIXME: check whether this is guaranteed.
|
|
if not block.function is None:
|
|
break
|
|
|
|
block = block.superblock
|
|
else:
|
|
# Assuming gdb 7.0 release.
|
|
file = tempfile.mkstemp(prefix="gdbpy_")
|
|
filename = file[1]
|
|
gdb.execute("set logging file %s" % filename)
|
|
gdb.execute("set logging redirect on")
|
|
gdb.execute("set logging on")
|
|
gdb.execute("info locals")
|
|
gdb.execute("info args")
|
|
gdb.execute("set logging off")
|
|
gdb.execute("set logging redirect off")
|
|
file = open(filename, "r")
|
|
for line in file:
|
|
if len(line) == 0 or line.startswith(" "):
|
|
continue
|
|
pos = line.find(" = ")
|
|
if pos < 0:
|
|
continue
|
|
name = line[0:pos]
|
|
item = Item(0, "local", name, name)
|
|
try:
|
|
item.value = frame.read_var(name) # this is a gdb value
|
|
except RuntimeError:
|
|
continue
|
|
items.append(item)
|
|
file.close()
|
|
os.remove(filename)
|
|
|
|
return items
|
|
|
|
|
|
def value(expr):
|
|
value = parseAndEvaluate(expr)
|
|
try:
|
|
return int(value)
|
|
except:
|
|
return str(value)
|
|
|
|
|
|
def isSimpleType(typeobj):
|
|
type = str(typeobj)
|
|
return type == "bool" \
|
|
or type == "char" \
|
|
or type == "double" \
|
|
or type == "float" \
|
|
or type == "int" \
|
|
or type == "long" or type.startswith("long ") \
|
|
or type == "short" or type.startswith("short ") \
|
|
or type == "signed" or type.startswith("signed ") \
|
|
or type == "unsigned" or type.startswith("unsigned ")
|
|
|
|
|
|
def isStringType(d, typeobj):
|
|
type = str(typeobj)
|
|
return type == d.ns + "QString" \
|
|
or type == d.ns + "QByteArray" \
|
|
or type == "std::string" \
|
|
or type == "std::wstring" \
|
|
or type == "wstring"
|
|
|
|
def warn(message):
|
|
if verbosity > 0:
|
|
print "XXX: %s " % message.encode("latin1")
|
|
pass
|
|
|
|
def check(exp):
|
|
if not exp:
|
|
raise RuntimeError("Check failed")
|
|
|
|
#def couldBePointer(p, align):
|
|
# type = gdb.lookup_type("unsigned int")
|
|
# ptr = gdb.Value(p).cast(type)
|
|
# d = int(str(ptr))
|
|
# warn("CHECKING : %s %d " % (p, ((d & 3) == 0 and (d > 1000 or d == 0))))
|
|
# return (d & (align - 1)) and (d > 1000 or d == 0)
|
|
|
|
|
|
def checkAccess(p, align = 1):
|
|
return p.dereference()
|
|
|
|
def checkContents(p, expected, align = 1):
|
|
if int(p.dereference()) != expected:
|
|
raise RuntimeError("Contents check failed")
|
|
|
|
def checkPointer(p, align = 1):
|
|
if not isNull(p):
|
|
p.dereference()
|
|
|
|
|
|
def isNull(p):
|
|
s = str(p)
|
|
return s == "0x0" or s.startswith("0x0 ")
|
|
|
|
movableTypes = set([
|
|
"QBrush", "QBitArray", "QByteArray",
|
|
"QCustomTypeInfo", "QChar",
|
|
"QDate", "QDateTime",
|
|
"QFileInfo", "QFixed", "QFixedPoint", "QFixedSize",
|
|
"QHashDummyValue",
|
|
"QIcon", "QImage",
|
|
"QLine", "QLineF", "QLatin1Char", "QLocal",
|
|
"QMatrix", "QModelIndex",
|
|
"QPoint", "QPointF", "QPen", "QPersistentModelIndex",
|
|
"QResourceRoot", "QRect", "QRectF", "QRegExp",
|
|
"QSize", "QSizeF", "QString",
|
|
"QTime", "QTextBlock",
|
|
"QUrl",
|
|
"QVariant",
|
|
"QXmlStreamAttribute", "QXmlStreamNamespaceDeclaration",
|
|
"QXmlStreamNotationDeclaration", "QXmlStreamEntityDeclaration"])
|
|
|
|
|
|
def stripClassTag(type):
|
|
if type.startswith("class "):
|
|
return type[6:]
|
|
return type
|
|
|
|
def checkPointerRange(p, n):
|
|
for i in xrange(0, n):
|
|
checkPointer(p)
|
|
++p
|
|
|
|
def call(value, func):
|
|
#warn("CALL: %s -> %s" % (value, func))
|
|
type = stripClassTag(str(value.type))
|
|
if type.find(":") >= 0:
|
|
type = "'" + type + "'"
|
|
exp = "((%s*)%s)->%s" % (type, value.address, func)
|
|
#warn("CALL: %s" % exp)
|
|
result = parseAndEvaluate(exp)
|
|
#warn(" -> %s" % result)
|
|
return result
|
|
|
|
def qtNamespace():
|
|
try:
|
|
type = str(parseAndEvaluate("&QString::null").type.target().unqualified())
|
|
return type[0:len(type) - len("QString::null")]
|
|
except RuntimeError:
|
|
return ""
|
|
|
|
def encodeCharArray(p, size):
|
|
s = ""
|
|
for i in xrange(0, size):
|
|
s += "%02x" % int(p.dereference())
|
|
p += 1
|
|
return s
|
|
|
|
def encodeByteArray(value):
|
|
d_ptr = value['d'].dereference()
|
|
data = d_ptr['data']
|
|
size = d_ptr['size']
|
|
alloc = d_ptr['alloc']
|
|
check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
|
|
check(d_ptr["ref"]["_q_value"] > 0)
|
|
if size > 0:
|
|
checkAccess(data, 4)
|
|
checkAccess(data + size) == 0
|
|
|
|
innerType = gdb.lookup_type("char")
|
|
p = gdb.Value(data.cast(innerType.pointer()))
|
|
return encodeCharArray(p, size)
|
|
|
|
def encodeString(value):
|
|
d_ptr = value['d'].dereference()
|
|
data = d_ptr['data']
|
|
size = d_ptr['size']
|
|
alloc = d_ptr['alloc']
|
|
check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
|
|
if size > 0:
|
|
checkAccess(data, 4)
|
|
checkAccess(data + size * 2) == 0
|
|
check(d_ptr["ref"]["_q_value"] > 0)
|
|
p = gdb.Value(d_ptr["data"])
|
|
s = ""
|
|
for i in xrange(0, size):
|
|
val = int(p.dereference())
|
|
s += "%02x" % (val % 256)
|
|
s += "%02x" % (val / 256)
|
|
p += 1
|
|
return s
|
|
|
|
#######################################################################
|
|
#
|
|
# Item
|
|
#
|
|
#######################################################################
|
|
|
|
class Item:
|
|
def __init__(self, value, parentiname, iname, name):
|
|
self.value = value
|
|
if iname is None:
|
|
self.iname = parentiname
|
|
else:
|
|
self.iname = "%s.%s" % (parentiname, iname)
|
|
self.name = name
|
|
|
|
|
|
#######################################################################
|
|
#
|
|
# FrameCommand
|
|
#
|
|
#######################################################################
|
|
|
|
class FrameCommand(gdb.Command):
|
|
"""Do fancy stuff. Usage bb --verbose expandedINames"""
|
|
|
|
def __init__(self):
|
|
super(FrameCommand, self).__init__("bb", gdb.COMMAND_OBSCURE)
|
|
|
|
def invoke(self, arg, from_tty):
|
|
args = arg.split(' ')
|
|
#warn("ARG: %s" % arg)
|
|
#warn("ARGS: %s" % args)
|
|
useFancy = int(args[0])
|
|
passExceptions = int(args[1])
|
|
expandedINames = set()
|
|
if len(args) > 2:
|
|
expandedINames = set(args[2].split(","))
|
|
#warn("EXPANDED INAMES: %s" % expandedINames)
|
|
module = sys.modules[__name__]
|
|
self.dumpers = {}
|
|
|
|
if useFancy == -1:
|
|
output = "dumpers=["
|
|
for key, value in module.__dict__.items():
|
|
if key.startswith("qdump__"):
|
|
if output != "dumpers=[":
|
|
output += ","
|
|
output += '"' + key[7:] + '"'
|
|
output += "],"
|
|
#output += "qtversion=[%d,%d,%d]"
|
|
output += "qtversion=[4,6,0],"
|
|
output += "namespace=\"%s\"," % qtNamespace()
|
|
output += "dumperversion=\"2.0\","
|
|
output += "sizes=[],"
|
|
output += "expressions=[]"
|
|
output += "]"
|
|
print output
|
|
return
|
|
|
|
|
|
if useFancy:
|
|
for key, value in module.__dict__.items():
|
|
#if callable(value):
|
|
if key.startswith("qdump__"):
|
|
self.dumpers[key[7:]] = value
|
|
|
|
d = Dumper()
|
|
d.dumpers = self.dumpers
|
|
d.passExceptions = passExceptions
|
|
d.ns = qtNamespace()
|
|
d.expandedINames = expandedINames
|
|
d.useFancy = useFancy
|
|
#warn(" NAMESPACE IS: '%s'" % d.ns)
|
|
|
|
#
|
|
# Locals
|
|
#
|
|
for item in listOfLocals():
|
|
#warn("ITEM %s: " % item.value)
|
|
|
|
type = item.value.type
|
|
if type.code == gdb.TYPE_CODE_PTR \
|
|
and item.name == "argv" and str(type) == "char **":
|
|
# Special handling for char** argv:
|
|
n = 0
|
|
p = item.value
|
|
while not isNull(p.dereference()) and n <= 100:
|
|
p += 1
|
|
n += 1
|
|
|
|
d.beginHash()
|
|
d.put('iname="%s",' % item.iname)
|
|
d.putName(item.name)
|
|
d.putItemCount(select(n <= 100, n, "> 100"))
|
|
d.putType(type)
|
|
d.putNumChild(n)
|
|
if d.isExpanded(item):
|
|
p = item.value
|
|
d.beginChildren(n)
|
|
for i in xrange(0, n):
|
|
value = p.dereference()
|
|
d.putItem(Item(value, item.iname, i, None))
|
|
p += 1
|
|
if n > 100:
|
|
d.putEllipsis()
|
|
d.endChildren()
|
|
d.endHash()
|
|
|
|
else:
|
|
# A "normal" local variable or parameter
|
|
d.beginHash()
|
|
d.put('iname="%s",' % item.iname)
|
|
d.put('addr="%s",' % item.value.address)
|
|
d.safePutItemHelper(item)
|
|
d.endHash()
|
|
|
|
d.pushOutput()
|
|
locals = d.safeoutput
|
|
|
|
|
|
#
|
|
# Watchers
|
|
#
|
|
d.safeoutput = ""
|
|
watchers = ""
|
|
if len(args) > 3:
|
|
watchers = base64.b16decode(args[3], True)
|
|
if len(watchers) > 0:
|
|
for watcher in watchers.split("$$"):
|
|
(exp, name) = watcher.split("$")
|
|
self.handleWatch(d, exp, name)
|
|
d.pushOutput()
|
|
watchers = d.safeoutput
|
|
|
|
print('locals={iname="local",name="Locals",value=" ",type=" ",'
|
|
+ 'children=[' + locals + ']},'
|
|
+ 'watchers={iname="watch",name="Watchers",value=" ",type=" ",'
|
|
+ 'children=[' + watchers + ']}')
|
|
|
|
|
|
def handleWatch(self, d, exp, name):
|
|
#warn("HANDLING WATCH %s, NAME: %s" % (exp, name))
|
|
if exp.startswith("["):
|
|
#warn("EVAL: EXP: %s" % exp)
|
|
d.beginHash()
|
|
d.put('iname="watch.%s",' % name)
|
|
d.put('name="%s",' % exp)
|
|
d.put('exp="%s"' % exp)
|
|
try:
|
|
list = eval(exp)
|
|
#warn("EVAL: LIST: %s" % list)
|
|
d.put('value=" "')
|
|
d.put('type=" "')
|
|
d.put('numchild="%d"' % len(list))
|
|
# This is a list of expressions to evaluate
|
|
d.beginChildren(len(list))
|
|
itemNumber = 0
|
|
for item in list:
|
|
self.handleWatch(d, item, "%s.%d" % (name, itemNumber))
|
|
itemNumber += 1
|
|
d.endChildren()
|
|
except:
|
|
warn("EVAL: ERROR CAUGHT")
|
|
d.put('value="<syntax error>"')
|
|
d.put('type=" "')
|
|
d.put('numchild="0"')
|
|
d.beginChildren(0)
|
|
d.endChildren()
|
|
d.endHash()
|
|
return
|
|
|
|
d.beginHash()
|
|
d.put('iname="watch.%s",' % name)
|
|
d.put('name="%s",' % exp)
|
|
d.put('exp="%s"' % exp)
|
|
handled = False
|
|
if exp == "<Edit>":
|
|
d.put(',value=" ",')
|
|
d.put('type=" ",numchild="0"')
|
|
else:
|
|
try:
|
|
value = parseAndEvaluate(exp)
|
|
item = Item(value, "watch", name, name)
|
|
d.safePutItemHelper(item)
|
|
except RuntimeError:
|
|
d.put(',value="<invalid>",')
|
|
d.put('type="<unknown>",numchild="0"')
|
|
d.endHash()
|
|
|
|
|
|
FrameCommand()
|
|
|
|
|
|
|
|
#######################################################################
|
|
#
|
|
# The Dumper Class
|
|
#
|
|
#######################################################################
|
|
|
|
class Dumper:
|
|
def __init__(self):
|
|
self.output = ""
|
|
self.safeoutput = ""
|
|
self.childTypes = [""]
|
|
self.childNumChilds = [-1]
|
|
|
|
def put(self, value):
|
|
self.output += value
|
|
|
|
def putCommaIfNeeded(self):
|
|
c = self.output[-1:]
|
|
if c == '}' or c == '"' or c == ']' or c == '\n':
|
|
self.put(',')
|
|
#warn("C:'%s' COND:'%d' OUT:'%s'" %
|
|
# (c, c == '}' or c == '"' or c == ']' or c == '\n', self.output))
|
|
|
|
def putField(self, name, value):
|
|
self.putCommaIfNeeded()
|
|
self.put('%s="%s"' % (name, value))
|
|
|
|
def beginHash(self):
|
|
self.putCommaIfNeeded()
|
|
self.put('{')
|
|
|
|
def endHash(self):
|
|
self.put('}')
|
|
|
|
def beginItem(self, name):
|
|
self.putCommaIfNeeded()
|
|
self.put(name)
|
|
self.put('="')
|
|
|
|
def endItem(self):
|
|
self.put('"')
|
|
|
|
def beginChildren(self, numChild = 1, type = None, children = None):
|
|
childType = ""
|
|
childNumChild = -1
|
|
if numChild == 0:
|
|
type = None
|
|
self.putCommaIfNeeded()
|
|
if not type is None:
|
|
childType = stripClassTag(str(type))
|
|
self.put('childtype="%s",' % childType)
|
|
if isSimpleType(type) or isStringType(self, type):
|
|
self.put('childnumchild="0",')
|
|
childNumChild = 0
|
|
elif type.code == gdb.TYPE_CODE_PTR:
|
|
self.put('childnumchild="1",')
|
|
childNumChild = 1
|
|
if not children is None:
|
|
self.put('childnumchild="%s",' % children)
|
|
childNumChild = children
|
|
self.childTypes.append(childType)
|
|
self.childNumChilds.append(childNumChild)
|
|
#warn("BEGIN: %s" % self.childTypes)
|
|
self.put("children=[")
|
|
|
|
def endChildren(self):
|
|
#warn("END: %s" % self.childTypes)
|
|
self.childTypes.pop()
|
|
self.childNumChilds.pop()
|
|
self.put(']')
|
|
|
|
# convenience
|
|
def putItemCount(self, count):
|
|
self.putCommaIfNeeded()
|
|
self.put('value="<%s items>"' % count)
|
|
|
|
def putEllipsis(self):
|
|
self.putCommaIfNeeded()
|
|
self.put('{name="<incomplete>",value="",type="",numchild="0"}')
|
|
|
|
def putType(self, type):
|
|
#warn("TYPES: '%s' '%s'" % (type, self.childTypes))
|
|
#warn(" EQUAL 2: %s " % (str(type) == self.childTypes[-1]))
|
|
type = stripClassTag(str(type))
|
|
if len(type) > 0 and type != self.childTypes[-1]:
|
|
self.putCommaIfNeeded()
|
|
self.put('type="%s"' % type) # str(type.unqualified()) ?
|
|
|
|
def putNumChild(self, numchild):
|
|
#warn("NUM CHILD: '%s' '%s'" % (numchild, self.childNumChilds[-1]))
|
|
if numchild != self.childNumChilds[-1]:
|
|
self.put(',numchild="%s"' % numchild)
|
|
|
|
def putValue(self, value, encoding = None):
|
|
if not encoding is None:
|
|
self.putField("valueencoded", encoding)
|
|
self.putField("value", value)
|
|
|
|
def putStringValue(self, value):
|
|
str = encodeString(value)
|
|
self.putCommaIfNeeded()
|
|
self.put('valueencoded="%d",value="%s"' % (7, str))
|
|
|
|
def putByteArrayValue(self, value):
|
|
str = encodeByteArray(value)
|
|
self.putCommaIfNeeded()
|
|
self.put('valueencoded="%d",value="%s"' % (6, str))
|
|
|
|
def putName(self, name):
|
|
self.putCommaIfNeeded()
|
|
self.put('name="%s"' % name)
|
|
|
|
def isExpanded(self, item):
|
|
#warn("IS EXPANDED: %s in %s" % (item.iname, self.expandedINames))
|
|
if item.iname is None:
|
|
raise "Illegal iname 'None'"
|
|
if item.iname.startswith("None"):
|
|
raise "Illegal iname '%s'" % item.iname
|
|
#warn(" --> %s" % (item.iname in self.expandedINames))
|
|
return item.iname in self.expandedINames
|
|
|
|
def isExpandedIName(self, iname):
|
|
return iname in self.expandedINames
|
|
|
|
def unputField(self, name):
|
|
pos = self.output.rfind(",")
|
|
if self.output[pos + 1:].startswith(name):
|
|
self.output = self.output[0:pos]
|
|
|
|
def stripNamespaceFromType(self, typeobj):
|
|
# This breaks for dumpers type names containing '__star'.
|
|
# But this should not happen as identifiers containing two
|
|
# subsequent underscores are reserved for the implemention.
|
|
if typeobj.code == gdb.TYPE_CODE_PTR:
|
|
return self.stripNamespaceFromType(typeobj.target()) + "__star"
|
|
# FIXME: pass ns from plugin
|
|
type = stripClassTag(str(typeobj))
|
|
if len(self.ns) > 0 and type.startswith(self.ns):
|
|
type = type[len(self.ns):]
|
|
pos = type.find("<")
|
|
if pos != -1:
|
|
type = type[0:pos]
|
|
return type
|
|
|
|
def isMovableType(self, type):
|
|
if type.code == gdb.TYPE_CODE_PTR:
|
|
return True
|
|
if isSimpleType(type):
|
|
return True
|
|
return self.stripNamespaceFromType(type) in movableTypes
|
|
|
|
def putIntItem(self, name, value):
|
|
self.beginHash()
|
|
self.putName(name)
|
|
self.putValue(value)
|
|
self.putType("int")
|
|
self.putNumChild(0)
|
|
self.endHash()
|
|
|
|
def putBoolItem(self, name, value):
|
|
self.beginHash()
|
|
self.putName(name)
|
|
self.putValue(value)
|
|
self.putType("bool")
|
|
self.putNumChild(0)
|
|
self.endHash()
|
|
|
|
def pushOutput(self):
|
|
#warn("PUSH OUTPUT: %s " % self.output)
|
|
self.safeoutput += self.output
|
|
self.output = ""
|
|
|
|
def dumpInnerValueHelper(self, item):
|
|
if isSimpleType(item.value.type):
|
|
self.safePutItemHelper(item)
|
|
|
|
def safePutItem(self, item):
|
|
self.beginHash()
|
|
self.safePutItemHelper(item)
|
|
self.endHash()
|
|
|
|
def safePutItemHelper(self, item):
|
|
self.pushOutput()
|
|
# This is only used at the top level to ensure continuation
|
|
# after failures due to uninitialized or corrupted data.
|
|
if self.passExceptions:
|
|
# for debugging reasons propagate errors.
|
|
self.putItemHelper(item)
|
|
|
|
else:
|
|
try:
|
|
self.putItemHelper(item)
|
|
|
|
except RuntimeError:
|
|
self.output = ""
|
|
# FIXME: Only catch debugger related exceptions
|
|
#exType, exValue, exTraceback = sys.exc_info()
|
|
#tb = traceback.format_exception(exType, exValue, exTraceback)
|
|
#warn("Exception: %s" % ex.message)
|
|
# DeprecationWarning: BaseException.message
|
|
# has been deprecated
|
|
#warn("Exception.")
|
|
#for line in tb:
|
|
# warn("%s" % line)
|
|
self.putName(item.name)
|
|
self.putValue("<invalid>")
|
|
self.putType(str(item.value.type))
|
|
self.putNumChild(0)
|
|
#if self.isExpanded(item):
|
|
self.beginChildren()
|
|
self.endChildren()
|
|
self.pushOutput()
|
|
|
|
def putItem(self, item):
|
|
self.beginHash()
|
|
self.safePutItemHelper(item)
|
|
self.endHash()
|
|
|
|
def putCallItem(self, name, item, func):
|
|
result = call(item.value, func)
|
|
self.putItem(Item(result, item.iname, name, name))
|
|
|
|
#def putItemOrPointerHelper(self, item):
|
|
# if item.value.type.code == gdb.TYPE_CODE_PTR \
|
|
# and str(item.value.type.target()) != "char":
|
|
# if not isNull(item.value):
|
|
# self.putItemOrPointerHelper(
|
|
# Item(item.value.dereference(), item.iname, None, None))
|
|
# else:
|
|
# self.putValue("(null)")
|
|
# self.putNumChild(0)
|
|
# else:
|
|
# self.safePutItemHelper(item)
|
|
|
|
|
|
def putItemHelper(self, item):
|
|
name = getattr(item, "name", None)
|
|
if not name is None:
|
|
self.putName(name)
|
|
|
|
# FIXME: Gui shows references stripped?
|
|
#warn("REAL INAME: %s " % item.iname)
|
|
#warn("REAL TYPE: %s " % item.value.type)
|
|
#warn("REAL VALUE: %s " % item.value)
|
|
|
|
value = item.value
|
|
type = value.type
|
|
|
|
if type.code == gdb.TYPE_CODE_REF:
|
|
type = type.target()
|
|
value = value.cast(type)
|
|
|
|
if type.code == gdb.TYPE_CODE_TYPEDEF:
|
|
type = type.target()
|
|
|
|
strippedType = self.stripNamespaceFromType(
|
|
type.strip_typedefs().unqualified()).replace("::", "__")
|
|
|
|
#warn(" STRIPPED: %s" % strippedType)
|
|
#warn(" DUMPERS: %s" % self.dumpers)
|
|
#warn(" DUMPERS: %s" % (strippedType in self.dumpers))
|
|
|
|
if isSimpleType(type):
|
|
#warn("IS SIMPLE: %s " % type)
|
|
self.putType(item.value.type)
|
|
self.putValue(value)
|
|
self.putNumChild(0)
|
|
|
|
elif strippedType in self.dumpers:
|
|
#warn("IS DUMPABLE: %s " % type)
|
|
self.putType(item.value.type)
|
|
self.dumpers[strippedType](self, item)
|
|
|
|
elif type.code == gdb.TYPE_CODE_ENUM:
|
|
#warn("GENERIC ENUM: %s" % value)
|
|
self.putType(item.value.type)
|
|
self.putValue(value)
|
|
self.putNumChild(0)
|
|
|
|
|
|
elif type.code == gdb.TYPE_CODE_PTR:
|
|
if self.useFancy:
|
|
#warn("A POINTER: %s" % value.type)
|
|
isHandled = False
|
|
if isNull(value):
|
|
self.putValue("0x0")
|
|
self.putType(item.value.type)
|
|
self.putNumChild(0)
|
|
isHandled = True
|
|
|
|
target = str(type.target().unqualified())
|
|
if target == "void" and not isHandled:
|
|
self.putType(item.value.type)
|
|
self.putValue(str(value))
|
|
self.putNumChild(0)
|
|
isHandled = True
|
|
|
|
if target == "char" and not isHandled:
|
|
# Display values up to given length directly
|
|
self.putType(item.value.type)
|
|
firstNul = -1
|
|
p = value
|
|
for i in xrange(0, 100):
|
|
if p.dereference() == 0:
|
|
# Found terminating NUL
|
|
self.putValue(encodeCharArray(value, i), "6")
|
|
self.putNumChild(0)
|
|
isHandled = True
|
|
break
|
|
p += 1
|
|
|
|
if not isHandled:
|
|
## Generic pointer type.
|
|
#warn("GENERIC POINTER: %s" % value)
|
|
innerType = item.value.type.target()
|
|
self.putType(innerType)
|
|
self.childTypes.append(
|
|
stripClassTag(str(innerType)))
|
|
#self.putType(item.value.type.target())
|
|
self.putItemHelper(
|
|
Item(item.value.dereference(), item.iname, None, None))
|
|
self.childTypes.pop()
|
|
else:
|
|
self.putType(item.value.type)
|
|
self.putValue(str(value.address))
|
|
self.putNumChild(1)
|
|
if self.isExpanded(item):
|
|
self.beginChildren()
|
|
self.putItem(
|
|
Item(item.value.dereference(), item.iname, "*", "*"))
|
|
self.endChildren()
|
|
|
|
else:
|
|
#warn("INAME: %s " % item.iname)
|
|
#warn("INAMES: %s " % self.expandedINames)
|
|
#warn("EXPANDED: %s " % (item.iname in self.expandedINames))
|
|
|
|
# insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=10953
|
|
#fields = value.type.fields()
|
|
fields = value.type.strip_typedefs().fields()
|
|
|
|
self.putType(item.value.type)
|
|
self.putValue("{...}")
|
|
|
|
if False:
|
|
numfields = 0
|
|
for field in fields:
|
|
bitpos = getattr(field, "bitpos", None)
|
|
if not bitpos is None:
|
|
++numfields
|
|
else:
|
|
numfields = len(fields)
|
|
self.putNumChild(numfields)
|
|
|
|
if self.isExpanded(item):
|
|
innerType = None
|
|
if len(fields) == 1 and fields[0].name is None:
|
|
innerType = value.type.target()
|
|
self.beginChildren(1, innerType)
|
|
|
|
baseNumber = 0
|
|
for field in fields:
|
|
#warn("FIELD: %s" % field)
|
|
#warn(" BITSIZE: %s" % field.bitsize)
|
|
#warn(" ARTIFICIAL: %s" % field.artificial)
|
|
bitpos = getattr(field, "bitpos", None)
|
|
if bitpos is None: # FIXME: Is check correct?
|
|
continue # A static class member(?).
|
|
|
|
if field.name is None:
|
|
innerType = value.type.target()
|
|
p = value.cast(innerType.pointer())
|
|
for i in xrange(0, value.type.sizeof / innerType.sizeof):
|
|
self.putItem(Item(p.dereference(), item.iname, i, None))
|
|
p = p + 1
|
|
continue
|
|
|
|
# ignore vtable pointers for virtual inheritance
|
|
if field.name.startswith("_vptr."):
|
|
continue
|
|
|
|
#warn("FIELD NAME: %s" % field.name)
|
|
#warn("FIELD TYPE: %s" % field.type)
|
|
if field.name == stripClassTag(str(field.type)):
|
|
# Field is base type. We cannot use field.name as part
|
|
# of the iname as it might contain spaces and other
|
|
# strange characters.
|
|
child = Item(value.cast(field.type),
|
|
item.iname, "@%d" % baseNumber, field.name)
|
|
baseNumber += 1
|
|
self.beginHash()
|
|
self.putField("iname", child.iname)
|
|
self.safePutItemHelper(child)
|
|
self.endHash()
|
|
else:
|
|
# Data member.
|
|
child = Item(value[field.name],
|
|
item.iname, field.name, field.name)
|
|
if not child.name:
|
|
child.name = "<anon>"
|
|
self.beginHash()
|
|
self.safePutItemHelper(child)
|
|
self.endHash()
|
|
self.endChildren()
|