Commit 17e8631d authored by hjk's avatar hjk

Debugger: Reorganize python dumper loading

- Split off GDB and LLDB specific parts into separate files,
- Trigger loading of dumpers.py and qttypes.py from bridge.py
- Read start up script at startup, not as part of dumper loading

Change-Id: I7941ee535121fa0f43a466e5bb75a18c9bb19764
Reviewed-by: default avatarhjk <hjk121@nokiamail.com>
parent 87f2d83e
This diff is collapsed.
......@@ -45,6 +45,15 @@ def removeTempFile(name):
except:
pass
def showException(msg, exType, exValue, exTraceback):
warn("**** CAUGHT EXCEPTION: %s ****" % msg)
try:
import traceback
for line in traceback.format_exception(exType, exValue, exTraceback):
warn("%s" % line)
except:
pass
verbosity = 0
verbosity = 1
......
def warn(message):
print "XXX: %s\n" % message.encode("latin1")
#######################################################################
#
# Infrastructure
#
#######################################################################
def savePrint(output):
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)
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):
savePrint(func(args))
Command()
def parseAndEvaluate(exp):
return gdb.parse_and_eval(exp)
def extractFields(value):
return value.type.fields()
## Insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=10953:
##fields = type.fields()
## Insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=11777:
##fields = defsype).fields()
## This seems to work.
##warn("TYPE 0: %s" % type)
#type = stripTypedefs(type)
#fields = type.fields()
#if len(fields):
# return fields
##warn("TYPE 1: %s" % type)
## This fails for arrays. See comment in lookupType.
#type0 = lookupType(str(type))
#if not type0 is None:
# type = type0
#if type.code == FunctionCode:
# return []
##warn("TYPE 2: %s" % type)
#fields = type.fields()
##warn("FIELDS: %s" % fields)
#return fields
def fieldCount(type):
return len(type.fields())
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 []
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
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
return items
def catchCliOutput(command):
try:
return gdb.execute(command, to_string=True).split("\n")
except:
pass
filename = 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)
removeTempFile(filename)
return "CLI ERROR: %s " % msg
temp = open(filename, "r")
lines = []
for line in temp:
lines.append(line)
temp.close()
removeTempFile(filename)
return lines
def selectedInferior():
try:
# Does not exist in 7.3.
return gdb.selected_inferior()
except:
pass
# gdb.Inferior is new in gdb 7.2
return gdb.inferiors()[0]
def readRawMemory(base, size):
try:
inferior = selectedInferior()
return binascii.hexlify(inferior.read_memory(base, size))
except:
pass
s = ""
t = lookupType("unsigned char").pointer()
base = base.cast(t)
for i in xrange(size):
s += "%02x" % int(base.dereference())
base += 1
return s
#######################################################################
#
# 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
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))
PPCommand()
# 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()
def scanStack(p, n):
p = long(p)
r = []
for i in xrange(n):
f = gdb.parse_and_eval("{void*}%s" % p)
m = gdb.execute("info symbol %s" % f, to_string=True)
if not m.startswith("No symbol matches"):
r.append(m)
p += f.type.sizeof
return r
class ScanStackCommand(gdb.Command):
def __init__(self):
super(ScanStackCommand, self).__init__("scanStack", gdb.COMMAND_OBSCURE)
def invoke(self, args, from_tty):
if len(args) == 0:
args = 20
savePrint(scanStack(gdb.parse_and_eval("$sp"), int(args)))
ScanStackCommand()
import json
#warn("LOADING LLDB")
# Data members
SimpleValueCode, \
StructCode, \
PointerCode \
= range(3)
# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h
UnknownType = 0
BreakpointByFileAndLine = 1
BreakpointByFunction = 2
BreakpointByAddress = 3
BreakpointAtThrow = 4
BreakpointAtCatch = 5
BreakpointAtMain = 6
BreakpointAtFork = 7
BreakpointAtExec = 8
BreakpointAtSysCall = 10
WatchpointAtAddress = 11
WatchpointAtExpression = 12
BreakpointOnQmlSignalEmit = 13
BreakpointAtJavaScriptThrow = 14
def dumpJson(stuff):
warn("%s" % json.dumps(stuff, sort_keys=True, indent=4, separators=(',', ': ')))
def registerCommand(name, func):
pass
class Type:
def __init__(self, var):
self.raw = var
if var.num_children == 0:
self.code = SimpleValueCode
else:
self.code = StructCode
self.value_type = var.value_type
def __str__(self):
#try:
return self.raw.type.name
#except:
# return "<illegal type>"
def fieldCount(self):
return self.raw.num_children
def unqualified(self):
return self
class Value:
def __init__(self, var):
self.raw = var
self.is_optimized_out = False
self.address = var.addr
self.type = Type(var)
self.name = var.name
def __str__(self):
return str(self.raw.value)
def fields(self):
return [Value(self.raw.GetChildAtIndex(i)) for i in range(self.raw.num_children)]
currentThread = None
currentFrame = None
def listOfLocals(varList):
global currentThread
global currentFrame
items = []
currentThread = lldb.process.GetThreadAtIndex(0)
currentFrame = currentThread.GetFrameAtIndex(0)
for var in currentFrame.variables:
item = LocalItem()
item.iname = "local." + var.name
item.name = var.name
item.value = Value(var)
items.append(item)
return items
def extractFields(value):
return value.fields()
def fieldCount(type):
return type.fieldCount();
def threadsData(options):
result = "threads={threads=["
for thread in lldb.process.threads:
result += "{id=\"%d\"" % thread.id
result += ",target-id=\"%s\"" % thread.id
result += ",index=\"%s\"" % thread.idx
result += ",stop-reason=\"%s\"" % thread.stop_reason
if thread.IsSuspended():
result += ",state=\"stopped\""
else:
result += ",state=\"running\""
if not thread.name is None:
result += ",name=\"%s\"" % thread.name
result += ",frame={"
frame = thread.GetFrameAtIndex(0)
result += "pc=\"%s\"" % frame.pc
result += ",addr=\"%s\"" % frame.pc
result += ",fp=\"%s\"" % frame.fp
result += ",func=\"%s\"" % frame.function.name
result += ",line=\"%s\"" % frame.line_entry.line
result += ",fullname=\"%s\"" % frame.line_entry.file
result += ",file=\"%s\"" % frame.line_entry.file
result += "}},"
result += "],current-thread-id=\"%s\"}" % lldb.process.selected_thread.id
return result
def stackData(options):
try:
thread = lldb.process.GetThreadById(options["threadid"])
except:
thread = lldb.process.GetThreadAtIndex(0)
result = "stack={frames=["
for frame in thread.frames:
result += "{pc=\"%s\"" % frame.pc
result += ",level=\"%d\"" % frame.idx
result += ",addr=\"%s\"" % frame.pc
result += ",fp=\"%s\"" % frame.fp
result += ",func=\"%s\"" % frame.function.name
result += ",line=\"%s\"" % frame.line_entry.line
result += ",fullname=\"%s\"" % frame.line_entry.file
result += ",usable=\"1\""
result += ",file=\"%s\"}," % frame.line_entry.file
hasmore = "0"
result += "],hasmore=\"%s\"}, " % hasmore
return result
def parseOptions(optionstring):
options = {}
for opt in optionstring.split(","):
try:
key, value = opt.split(":")
options[key] = value
except:
pass
return options
def updateData(parts, localsOptions, stackOptions, threadOptions):
result = "";
if parts & 1:
result += bb(localsOptions) + ","
if parts & 2:
result += stackData(parseOptions(stackOptions))
if parts & 4:
result += threadsData(parseOptions(threadOptions))
return result
def listModules():
result = "modules={"
for module in lldb.target.modules:
result += "{file=\"%s\"" % module.file.fullpath
result += ",name=\"%s\"" % module.file.basename
#result += ",addrsize=\"%s\"" % module.addr_size
#result += ",triple=\"%s\"" % module.triple
#result += ",sections={"
#for section in module.sections:
# result += "[name=\"%s\"" % section.name
# result += ",addr=\"%s\"" % section.addr
# result += ",size=\"%s\"]," % section.size
#result += "}"
result += "},"
result += "]"
return result
def breakpoint_function_wrapper(baton, process, frame, bp_loc):
result = "*stopped"
result += ",line=\"%s\"" % frame.line_entry.line
result += ",file=\"%s\"" % frame.line_entry.file
warn("WRAPPER: %s " %result)
return result
def initLldb():
pass
def dumpBreakpoint(bp, modelId):
cond = bp.GetCondition()
result = "{lldbid=\"%s\"" % bp.GetID()
result += ",modelid=\"%s\"" % modelId
result += ",hitcount=\"%s\"" % bp.GetHitCount()
result += ",threadid=\"%s\"" % bp.GetThreadID()
result += ",oneshot=\"%s\"" % (1 if bp.IsOneShot() else 0)
result += ",enabled=\"%s\"" % (1 if bp.IsEnabled() else 0)
result += ",valid=\"%s\"" % (1 if bp.IsValid() else 0)
result += ",condition=\"%s\"" % ("" if cond is None else cond)
result += ",ignorecount=\"%s\"" % bp.GetIgnoreCount()
result += ",locations=["
for i in range(bp.GetNumLocations()):
loc = bp.GetLocationAtIndex(i)
addr = loc.GetAddress()
result += "{locid=\"%s\"" % loc.GetID()
result += ",func=\"%s\"" % addr.GetFunction().GetName()
result += ",enabled=\"%s\"" % (1 if loc.IsEnabled() else 0)
result += ",resolved=\"%s\"" % (1 if loc.IsResolved() else 0)
result += ",valid=\"%s\"" % (1 if loc.IsValid() else 0)
result += ",ignorecount=\"%s\"" % loc.GetIgnoreCount()
result += ",addr=\"%s\"}," % loc.GetLoadAddress()
result += "]},"
return result
def onBreak():
lldb.debugger.HandleCommand("settings set frame-format ''")
lldb.debugger.HandleCommand("settings set thread-format ''")
result = "*stopped,frame={....}"
print result
def handleBreakpoints(stuff):
todo = json.loads(stuff)
#dumpJson(todo)
#target = lldb.debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT)
target = lldb.debugger.GetTargetAtIndex(0)
#target = lldb.target
result = "bkpts={added=["
for bp in todo["add"]:
bpType = bp["type"]
if bpType == BreakpointByFileAndLine:
bpNew = target.BreakpointCreateByLocation(str(bp["file"]), int(bp["line"]))
elif bpType == BreakpointByFunction:
bpNew = target.BreakpointCreateByName(bp["function"])
elif bpType == BreakpointAtMain:
bpNew = target.BreakpointCreateByName("main", target.GetExecutable().GetFilename())
bpNew.SetIgnoreCount(int(bp["ignorecount"]))
bpNew.SetCondition(str(bp["condition"]))
bpNew.SetEnabled(int(bp["enabled"]))
bpNew.SetOneShot(int(bp["oneshot"]))
#bpNew.SetCallback(breakpoint_function_wrapper, None)
#bpNew.SetCallback(breakpoint_function_wrapper, None)
#"breakpoint command add 1 -o \"import time; print time.asctime()\"
#cmd = "script print(11111111)"
cmd = "continue"
lldb.debugger.HandleCommand(
"breakpoint command add -o 'script onBreak()' %s" % bpNew.GetID())
result += dumpBreakpoint(bpNew, bp["modelid"])
result += "],changed=["
for bp in todo["change"]:
bpChange = target.FindBreakpointByID(int(bp["lldbid"]))
bpChange.SetIgnoreCount(int(bp["ignorecount"]))
bpChange.SetCondition(str(bp["condition"]))
bpChange.SetEnabled(int(bp["enabled"]))
bpChange.SetOneShot(int(bp["oneshot"]))
result += dumpBreakpoint(bpChange, bp["modelid"])
result += "],removed=["
for bp in todo["remove"]:
bpDead = target.BreakpointDelete(int(bp["lldbid"]))
result += "{modelid=\"%s\"}" % bp["modelid"]
result += "]}"
return result
def doStepOver():
lldb.debugger.SetAsync(False)
lldb.thread.StepOver()
lldb.debugger.SetAsync(True)
result = "result={"
result += "},"
result += stackData({'threadid': lldb.process.selected_thread.id})
result += threadsData({})
return result
def doInterrupt():
lldb.debugger.SetAsync(False)
lldb.process.Stop()
lldb.debugger.SetAsync(True)
result = "result={"
result += "}"