debugger: refactor the dumper class to make it work with gdb 7.0

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.
This commit is contained in:
hjk
2009-12-09 09:53:43 +01:00
parent c311ab0a4f
commit 68bd4d2b95
3 changed files with 127 additions and 76 deletions

View File

@@ -9,6 +9,10 @@ import gdb
import base64 import base64
import curses.ascii import curses.ascii
# only needed for gdb 7.0
import os
import tempfile
verbosity = 0 verbosity = 0
verbosity = 1 verbosity = 1
@@ -22,13 +26,95 @@ def qmin(n, m):
return n return n
return m 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): def value(expr):
value = gdb.parse_and_eval(expr) value = parseAndEvaluate(expr)
try: try:
return int(value) return int(value)
except: except:
return str(value) return str(value)
def isSimpleType(typeobj): def isSimpleType(typeobj):
type = str(typeobj) type = str(typeobj)
return type == "bool" \ return type == "bool" \
@@ -41,6 +127,7 @@ def isSimpleType(typeobj):
or type == "signed" or type.startswith("signed ") \ or type == "signed" or type.startswith("signed ") \
or type == "unsigned" or type.startswith("unsigned ") or type == "unsigned" or type.startswith("unsigned ")
def isStringType(d, typeobj): def isStringType(d, typeobj):
type = str(typeobj) type = str(typeobj)
return type == d.ns + "QString" \ return type == d.ns + "QString" \
@@ -114,17 +201,17 @@ def checkPointerRange(p, n):
def call(value, func): def call(value, func):
#warn("CALL: %s -> %s" % (value, func)) #warn("CALL: %s -> %s" % (value, func))
type = stripClassTag(str(value.type)) type = stripClassTag(str(value.type))
if type.find(':') >= 0: if type.find(":") >= 0:
type = "'" + type + "'" type = "'" + type + "'"
exp = "((%s*)%s)->%s" % (type, value.address, func) exp = "((%s*)%s)->%s" % (type, value.address, func)
#warn("CALL: %s" % exp) #warn("CALL: %s" % exp)
result = gdb.parse_and_eval(exp) result = parseAndEvaluate(exp)
#warn(" -> %s" % result) #warn(" -> %s" % result)
return result return result
def qtNamespace(): def qtNamespace():
try: try:
type = str(gdb.parse_and_eval("&QString::null").type.target().unqualified()) type = str(parseAndEvaluate("&QString::null").type.target().unqualified())
return type[0:len(type) - len("QString::null")] return type[0:len(type) - len("QString::null")]
except RuntimeError: except RuntimeError:
return "" return ""
@@ -247,79 +334,44 @@ class FrameCommand(gdb.Command):
# #
# Locals # Locals
# #
try: for item in listOfLocals():
frame = gdb.selected_frame() #warn("ITEM %s: " % item.value)
#warn("FRAME %s: " % frame)
except RuntimeError:
return ""
block = frame.block() type = item.value.type
while True: if type.code == gdb.TYPE_CODE_PTR \
if block is None: and item.name == "argv" and str(type) == "char **":
warn("UNEXPECTED 'None' BLOCK") # Special handling for char** argv:
break n = 0
for symbol in block: p = item.value
name = symbol.print_name while not isNull(p.dereference()) and n <= 100:
p += 1
n += 1
if name == "__in_chrg": d.beginHash()
continue d.put('iname="%s",' % item.iname)
d.putName(item.name)
# "NotImplementedError: Symbol type not yet supported in d.putItemCount(select(n <= 100, n, "> 100"))
# Python scripts." d.putType(type)
#warn("SYMBOL %s: " % symbol.value) d.putNumChild(n)
#warn("SYMBOL %s (%s): " % (symbol, name)) if d.isExpanded(item):
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)
type = item.value.type
if type.code == gdb.TYPE_CODE_PTR \
and name == "argv" and str(type) == "char **":
# Special handling for char** argv:
n = 0
p = item.value p = item.value
while not isNull(p.dereference()) and n <= 100: d.beginChildren(n)
for i in xrange(0, n):
value = p.dereference()
d.putItem(Item(value, item.iname, i, None))
p += 1 p += 1
n += 1 if n > 100:
d.putEllipsis()
d.endChildren()
d.endHash()
d.beginHash() else:
d.put('iname="%s",' % item.iname) # A "normal" local variable or parameter
d.putName(name) d.beginHash()
d.putItemCount(select(n <= 100, n, "> 100")) d.put('iname="%s",' % item.iname)
d.putType(type) d.put('addr="%s",' % item.value.address)
d.putNumChild(n) d.safePutItemHelper(item)
if d.isExpanded(item): d.endHash()
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()
# 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
#warn("BLOCK %s: " % block)
d.pushOutput() d.pushOutput()
locals = d.safeoutput locals = d.safeoutput
@@ -386,7 +438,7 @@ class FrameCommand(gdb.Command):
d.put('type=" ",numchild="0"') d.put('type=" ",numchild="0"')
else: else:
try: try:
value = gdb.parse_and_eval(exp) value = parseAndEvaluate(exp)
item = Item(value, "watch", name, name) item = Item(value, "watch", name, name)
d.safePutItemHelper(item) d.safePutItemHelper(item)
except RuntimeError: except RuntimeError:

View File

@@ -613,7 +613,6 @@ def qdump__QObject(d, item):
# % (d.ns, item.value.address, propertyName) # % (d.ns, item.value.address, propertyName)
#exp = '"((\'%sQObject\'*)%s)"' % (d.ns, item.value.address,) #exp = '"((\'%sQObject\'*)%s)"' % (d.ns, item.value.address,)
#warn("EXPRESSION: %s" % exp) #warn("EXPRESSION: %s" % exp)
#value = gdb.parse_and_eval(exp)
value = call(item.value, 'property("%s")' % propertyName) value = call(item.value, 'property("%s")' % propertyName)
warn("VALUE: %s" % value) warn("VALUE: %s" % value)
warn("TYPE: %s" % value.type) warn("TYPE: %s" % value.type)

View File

@@ -4365,8 +4365,8 @@ bool GdbEngine::startGdb(const QStringList &args, const QString &gdb, const QStr
postCommand(_("show version"), CB(handleShowVersion)); postCommand(_("show version"), CB(handleShowVersion));
postCommand(_("source -p ") + dumperSourcePath + _("dumper.py")); postCommand(_("python execfile('%1dumper.py')").arg(dumperSourcePath));
postCommand(_("source -p ") + dumperSourcePath + _("gdbmacros.py")); postCommand(_("python execfile('%1gdbmacros.py')").arg(dumperSourcePath));
postCommand(_("-interpreter-exec console \"help bb\""), postCommand(_("-interpreter-exec console \"help bb\""),
CB(handleIsSynchroneous)); CB(handleIsSynchroneous));