Files
qt-creator/share/qtcreator/dumper/bridge.py
hjk 73fdc207ce debugger: make dumper more robust in optimized code
Change-Id: Ia398caf0fd29e6ac77502d870e8c9b615d4f395e
Reviewed-by: hjk <qthjk@ovi.com>
2012-01-06 16:58:38 +01:00

363 lines
12 KiB
Python

cdbLoaded = False
lldbLoaded = False
gdbLoaded = False
try:
#import cdb_bridge
cdbLoaded = True
except:
pass
try:
#import lldb_bridge
lldbLoaded = True
except:
pass
try:
import gdb
gdbLoaded = True
#######################################################################
#
# Infrastructure
#
#######################################################################
def registerCommand(name, func):
class Command(gdb.Command):
def __init__(self):
super(Command, self).__init__(name, gdb.COMMAND_OBSCURE)
def invoke(self, args, from_tty):
output = func(args)
try:
print(output)
except:
out = ""
for c in output:
cc = ord(c)
if cc > 127:
out += "\\\\%d" % cc
elif cc < 0:
out += "\\\\%d" % (cc + 256)
else:
out += c
print(out)
Command()
def isGoodGdb():
#return gdb.VERSION.startswith("6.8.50.2009") \
# and gdb.VERSION != "6.8.50.20090630-cvs"
return 'parse_and_eval' in __builtin__.dir(gdb)
def parseAndEvaluate(exp):
if isGoodGdb():
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")
try:
gdb.execute("print %s" % exp)
except:
gdb.execute("set logging off")
gdb.execute("set logging redirect off")
return None
gdb.execute("set logging off")
gdb.execute("set logging redirect off")
return gdb.history(0)
def listOfLocals(varList):
frame = gdb.selected_frame()
try:
frame = gdb.selected_frame()
#warn("FRAME %s: " % frame)
except RuntimeError, error:
warn("FRAME NOT ACCESSIBLE: %s" % error)
return []
except:
warn("FRAME NOT ACCESSIBLE FOR UNKNOWN REASONS")
return []
# New in 7.2
hasBlock = 'block' in __builtin__.dir(frame)
items = []
#warn("HAS BLOCK: %s" % hasBlock)
if hasBlock and isGoodGdb():
#warn("IS GOOD: %s " % varList)
try:
block = frame.block()
#warn("BLOCK: %s " % block)
except RuntimeError, error:
warn("BLOCK IN FRAME NOT ACCESSIBLE: %s" % error)
return items
except:
warn("BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS")
return items
shadowed = {}
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 (%s): " % (symbol, name))
if name in shadowed:
level = shadowed[name]
name1 = "%s@%s" % (name, level)
shadowed[name] = level + 1
else:
name1 = name
shadowed[name] = 1
#warn("SYMBOL %s (%s, %s)): " % (symbol, name, symbol.name))
item = LocalItem()
item.iname = "local." + name1
item.name = name1
try:
item.value = frame.read_var(name, block)
#warn("READ 1: %s" % item.value)
if not item.value.is_optimized_out:
#warn("ITEM 1: %s" % item.value)
items.append(item)
continue
except:
pass
try:
item.value = frame.read_var(name)
#warn("READ 2: %s" % item.value)
if not item.value.is_optimized_out:
#warn("ITEM 2: %s" % item.value)
items.append(item)
continue
except:
# RuntimeError: happens for
# void foo() { std::string s; std::wstring w; }
# ValueError: happens for (as of 2010/11/4)
# a local struct as found e.g. in
# gcc sources in gcc.c, int execute()
pass
try:
#warn("READ 3: %s %s" % (name, item.value))
item.value = gdb.parse_and_eval(name)
#warn("ITEM 3: %s" % item.value)
items.append(item)
except:
# Can happen in inlined code (see last line of
# RowPainter::paintChars(): "RuntimeError:
# No symbol \"__val\" in current context.\n"
pass
# 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 or 6.8-symbianelf.
filename, file = createTempFile()
#warn("VARLIST: %s " % varList)
#warn("FILENAME: %s " % filename)
gdb.execute("set logging off")
gdb.execute("set logging redirect off")
gdb.execute("set logging file %s" % filename)
gdb.execute("set logging redirect on")
gdb.execute("set logging on")
try:
gdb.execute("info args")
# We cannot use "info locals" as at least 6.8-symbianelf
# aborts as soon as we hit unreadable memory.
# gdb.execute("interpreter mi '-stack-list-locals 0'")
# results in &"Recursive internal problem.\n", so we have
# the frontend pass us the list of locals.
# There are two cases, either varList is empty, so we have
# to fetch the list here, or it is not empty with the
# first entry being a dummy.
if len(varList) == 0:
gdb.execute("info locals")
else:
varList = varList[1:]
except:
pass
gdb.execute("set logging off")
gdb.execute("set logging redirect off")
try:
temp = open(filename, "r")
for line in temp:
if len(line) == 0 or line.startswith(" "):
continue
# The function parameters
pos = line.find(" = ")
if pos < 0:
continue
varList.append(line[0:pos])
temp.close()
except:
pass
removeTempFile(filename, file)
#warn("VARLIST: %s " % varList)
for name in varList:
#warn("NAME %s " % name)
item = LocalItem()
item.iname = "local." + name
item.name = name
try:
item.value = frame.read_var(name) # this is a gdb value
except RuntimeError:
pass
#continue
except:
# Something breaking the list, like intermediate gdb warnings
# like 'Warning: can't find linker symbol for virtual table for
# `std::less<char const*>' value\n\nwarning: found
# `myns::QHashData::shared_null' instead [...]
# that break subsequent parsing. Chicken out and take the
# next "usable" line.
continue
items.append(item)
return items
def catchCliOutput(command):
try:
return gdb.execute(command, to_string=True).split("\n")
except:
pass
filename, file = createTempFile()
gdb.execute("set logging off")
gdb.execute("set logging redirect off")
gdb.execute("set logging file %s" % filename)
gdb.execute("set logging redirect on")
gdb.execute("set logging on")
msg = ""
try:
gdb.execute(command)
except RuntimeError, error:
# For the first phase of core file loading this yield
# "No symbol table is loaded. Use the \"file\" command."
msg = str(error)
except:
msg = "Unknown error"
gdb.execute("set logging off")
gdb.execute("set logging redirect off")
if len(msg):
# Having that might confuse result handlers in the gdbengine.
#warn("CLI ERROR: %s " % msg)
return "CLI ERROR: %s " % msg
temp = open(filename, "r")
lines = []
for line in temp:
lines.append(line)
temp.close()
removeTempFile(filename, file)
return lines
#######################################################################
#
# Types
#
#######################################################################
PointerCode = gdb.TYPE_CODE_PTR
ArrayCode = gdb.TYPE_CODE_ARRAY
StructCode = gdb.TYPE_CODE_STRUCT
UnionCode = gdb.TYPE_CODE_UNION
EnumCode = gdb.TYPE_CODE_ENUM
FlagsCode = gdb.TYPE_CODE_FLAGS
FunctionCode = gdb.TYPE_CODE_FUNC
IntCode = gdb.TYPE_CODE_INT
FloatCode = gdb.TYPE_CODE_FLT # Parts of GDB assume that this means complex.
VoidCode = gdb.TYPE_CODE_VOID
#SetCode = gdb.TYPE_CODE_SET
RangeCode = gdb.TYPE_CODE_RANGE
StringCode = gdb.TYPE_CODE_STRING
#BitStringCode = gdb.TYPE_CODE_BITSTRING
#ErrorTypeCode = gdb.TYPE_CODE_ERROR
MethodCode = gdb.TYPE_CODE_METHOD
#MethodPointerCode = gdb.TYPE_CODE_METHODPTR
#MemberPointerCode = gdb.TYPE_CODE_MEMBERPTR
ReferenceCode = gdb.TYPE_CODE_REF
CharCode = gdb.TYPE_CODE_CHAR
BoolCode = gdb.TYPE_CODE_BOOL
ComplexCode = gdb.TYPE_CODE_COMPLEX # Fortran ?
TypedefCode = gdb.TYPE_CODE_TYPEDEF
NamespaceCode = gdb.TYPE_CODE_NAMESPACE
#Code = gdb.TYPE_CODE_DECFLOAT # Decimal floating point.
#Code = gdb.TYPE_CODE_MODULE # Fortran
#Code = gdb.TYPE_CODE_INTERNAL_FUNCTION
#######################################################################
#
# Step Command
#
#######################################################################
def sal(args):
(cmd, addr) = args.split(",")
lines = catchCliOutput("info line *" + addr)
fromAddr = "0x0"
toAddr = "0x0"
for line in lines:
pos0from = line.find(" starts at address") + 19
pos1from = line.find(" ", pos0from)
pos0to = line.find(" ends at", pos1from) + 9
pos1to = line.find(" ", pos0to)
if pos1to > 0:
fromAddr = line[pos0from : pos1from]
toAddr = line[pos0to : pos1to]
gdb.execute("maint packet sal%s,%s,%s" % (cmd,fromAddr, toAddr))
registerCommand("sal", sal)
#######################################################################
#
# Convenience
#
#######################################################################
# Just convienience for 'python print ...'
class PPCommand(gdb.Command):
def __init__(self):
super(PPCommand, self).__init__("pp", gdb.COMMAND_OBSCURE)
def invoke(self, args, from_tty):
print(eval(args))
registerCommand("pp", pp)
# Just convienience for 'python print gdb.parse_and_eval(...)'
class PPPCommand(gdb.Command):
def __init__(self):
super(PPPCommand, self).__init__("ppp", gdb.COMMAND_OBSCURE)
def invoke(self, args, from_tty):
print(gdb.parse_and_eval(args))
PPPCommand()
except:
pass