forked from qt-creator/qt-creator
Libraries start using embedded gdb scripts of varying robustness causing unwanted side effects on debugging, so better avoid them. This choice can be overridden by the user in the startup script. Change-Id: I90ba4d733e4fdd7d2d4085eefb159f7c5e68326a Reviewed-by: hjk <qthjk@ovi.com>
372 lines
13 KiB
Python
372 lines
13 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
|
|
|
|
#######################################################################
|
|
#
|
|
# Sanitize environment
|
|
#
|
|
#######################################################################
|
|
|
|
gdb.execute("set auto-load-scripts no")
|
|
|
|
|
|
#######################################################################
|
|
#
|
|
# 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
|
|
|