forked from qt-creator/qt-creator
Debugger: Start moving PdbEngine to event based parsing
Change-Id: I63e06045b54226636280678ae7db8326a3e5f02e Reviewed-by: hjk <hjk@theqtcompany.com>
This commit is contained in:
@@ -1,252 +1,284 @@
|
|||||||
|
|
||||||
import pdb;
|
import pdb
|
||||||
import sys;
|
import sys
|
||||||
import linecache
|
import linecache
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
|
||||||
|
class Dumper:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def updateData(self, args):
|
||||||
|
self.expandedINames = set(args.get("expanded", []))
|
||||||
|
self.typeformats = args.get("typeformats", {})
|
||||||
|
self.formats = args.get("formats", {})
|
||||||
|
self.watchers = args.get("watchers", {})
|
||||||
|
self.output = "data={"
|
||||||
|
# self.handleListModules()
|
||||||
|
# self.handleListSymbols(expanded)
|
||||||
|
|
||||||
|
# Trigger error to get a backtrace.
|
||||||
|
frame = None
|
||||||
|
#self.warn("frame: %s" % frame)
|
||||||
|
try:
|
||||||
|
raise ZeroDivisionError
|
||||||
|
except ZeroDivisionError:
|
||||||
|
frame = sys.exc_info()[2].tb_frame.f_back
|
||||||
|
|
||||||
|
limit = 30
|
||||||
|
n = 0
|
||||||
|
isActive = False
|
||||||
|
while frame is not None and n < limit:
|
||||||
|
#self.warn("frame: %s" % frame.f_locals.keys())
|
||||||
|
lineno = frame.f_lineno
|
||||||
|
code = frame.f_code
|
||||||
|
filename = code.co_filename
|
||||||
|
name = code.co_name
|
||||||
|
if isActive:
|
||||||
|
linecache.checkcache(filename)
|
||||||
|
line = linecache.getline(filename, lineno, frame.f_globals)
|
||||||
|
self.dumpFrame(frame)
|
||||||
|
if name == "<module>":
|
||||||
|
isActive = False
|
||||||
|
if name == "trace_dispatch":
|
||||||
|
isActive = True
|
||||||
|
frame = frame.f_back
|
||||||
|
n = n + 1
|
||||||
|
#sys.stdout.flush()
|
||||||
|
|
||||||
|
self.output += '}'
|
||||||
|
sys.stdout.write(self.output)
|
||||||
|
|
||||||
|
def put(self, value):
|
||||||
|
#sys.stdout.write(value)
|
||||||
|
self.output += value
|
||||||
|
|
||||||
|
def putField(self, name, value):
|
||||||
|
self.put('%s="%s",' % (name, value))
|
||||||
|
|
||||||
|
def putItemCount(self, count):
|
||||||
|
self.put('value="<%s items>",' % count)
|
||||||
|
|
||||||
|
def putEllipsis(self):
|
||||||
|
self.put('{name="<incomplete>",value="",type="",numchild="0"},')
|
||||||
|
|
||||||
|
def cleanType(self, type):
|
||||||
|
t = str(type)
|
||||||
|
if t.startswith("<type '") and t.endswith("'>"):
|
||||||
|
t = t[7:-2]
|
||||||
|
if t.startswith("<class '") and t.endswith("'>"):
|
||||||
|
t = t[8:-2]
|
||||||
|
return t
|
||||||
|
|
||||||
|
def putType(self, type, priority = 0):
|
||||||
|
self.putField("type", self.cleanType(type))
|
||||||
|
|
||||||
|
def putAddress(self, addr):
|
||||||
|
self.put('addr="%s",' % cleanAddress(addr))
|
||||||
|
|
||||||
|
def putNumChild(self, numchild):
|
||||||
|
self.put('numchild="%s",' % numchild)
|
||||||
|
|
||||||
|
def putValue(self, value, encoding = None, priority = 0):
|
||||||
|
self.putField("value", value)
|
||||||
|
|
||||||
|
def putName(self, name):
|
||||||
|
self.put('name="%s",' % name)
|
||||||
|
|
||||||
|
def isExpanded(self, iname):
|
||||||
|
#self.warn("IS EXPANDED: %s in %s" % (iname, self.expandedINames))
|
||||||
|
if iname.startswith("None"):
|
||||||
|
raise "Illegal iname '%s'" % iname
|
||||||
|
#self.warn(" --> %s" % (iname in self.expandedINames))
|
||||||
|
return iname in self.expandedINames
|
||||||
|
|
||||||
|
def isExpandedIName(self, iname):
|
||||||
|
return iname in self.expandedINames
|
||||||
|
|
||||||
|
def itemFormat(self, item):
|
||||||
|
format = self.formats.get(str(cleanAddress(item.value.address)))
|
||||||
|
if format is None:
|
||||||
|
format = self.typeformats.get(self.stripClassTag(str(item.value.type)))
|
||||||
|
return format
|
||||||
|
|
||||||
|
def dumpFrame(self, frame):
|
||||||
|
for var in frame.f_locals.keys():
|
||||||
|
if var == "__file__":
|
||||||
|
continue
|
||||||
|
#if var == "__name__":
|
||||||
|
# continue
|
||||||
|
if var == "__package__":
|
||||||
|
continue
|
||||||
|
if var == "qdebug":
|
||||||
|
continue
|
||||||
|
if var != '__builtins__':
|
||||||
|
value = frame.f_locals[var]
|
||||||
|
self.dumpValue(value, var, "local.%s" % var)
|
||||||
|
|
||||||
|
def dumpValue(self, value, name, iname):
|
||||||
|
t = type(value)
|
||||||
|
tt = self.cleanType(t)
|
||||||
|
if tt == "module" or tt == "function":
|
||||||
|
return
|
||||||
|
if str(value).startswith("<class '"):
|
||||||
|
return
|
||||||
|
# FIXME: Should we?
|
||||||
|
if str(value).startswith("<enum-item "):
|
||||||
|
return
|
||||||
|
self.put("{")
|
||||||
|
self.putField("iname", iname)
|
||||||
|
self.putName(name)
|
||||||
|
self.putType(tt)
|
||||||
|
if tt == "NoneType":
|
||||||
|
self.putValue("None")
|
||||||
|
self.putNumChild(0)
|
||||||
|
elif tt == "list" or tt == "tuple":
|
||||||
|
self.putItemCount(len(value))
|
||||||
|
#self.putValue(value)
|
||||||
|
self.put("children=[")
|
||||||
|
for i in xrange(len(value)):
|
||||||
|
self.dumpValue(value[i], str(i), "%s.%d" % (iname, i))
|
||||||
|
self.put("]")
|
||||||
|
elif tt == "str":
|
||||||
|
v = value
|
||||||
|
self.putValue(v.encode('hex'))
|
||||||
|
self.putField("valueencoded", 6)
|
||||||
|
self.putNumChild(0)
|
||||||
|
elif tt == "unicode":
|
||||||
|
v = value
|
||||||
|
self.putValue(v.encode('hex'))
|
||||||
|
self.putField("valueencoded", 6)
|
||||||
|
self.putNumChild(0)
|
||||||
|
elif tt == "buffer":
|
||||||
|
v = str(value)
|
||||||
|
self.putValue(v.encode('hex'))
|
||||||
|
self.putField("valueencoded", 6)
|
||||||
|
self.putNumChild(0)
|
||||||
|
elif tt == "xrange":
|
||||||
|
b = iter(value).next()
|
||||||
|
e = b + len(value)
|
||||||
|
self.putValue("(%d, %d)" % (b, e))
|
||||||
|
self.putNumChild(0)
|
||||||
|
elif tt == "dict":
|
||||||
|
self.putItemCount(len(value))
|
||||||
|
self.putField("childnumchild", 2)
|
||||||
|
self.put("children=[")
|
||||||
|
i = 0
|
||||||
|
for (k, v) in value.iteritems():
|
||||||
|
self.put("{")
|
||||||
|
self.putType(" ")
|
||||||
|
self.putValue("%s: %s" % (k, v))
|
||||||
|
if self.isExpanded(iname):
|
||||||
|
self.put("children=[")
|
||||||
|
self.dumpValue(k, "key", "%s.%d.k" % (iname, i))
|
||||||
|
self.dumpValue(v, "value", "%s.%d.v" % (iname, i))
|
||||||
|
self.put("]")
|
||||||
|
self.put("},")
|
||||||
|
i += 1
|
||||||
|
self.put("]")
|
||||||
|
elif tt == "class":
|
||||||
|
pass
|
||||||
|
elif tt == "module":
|
||||||
|
pass
|
||||||
|
elif tt == "function":
|
||||||
|
pass
|
||||||
|
elif str(value).startswith("<enum-item "):
|
||||||
|
# FIXME: Having enums always shown like this is not nice.
|
||||||
|
self.putValue(str(value)[11:-1])
|
||||||
|
self.putNumChild(0)
|
||||||
|
else:
|
||||||
|
v = str(value)
|
||||||
|
p = v.find(" object at ")
|
||||||
|
if p > 1:
|
||||||
|
v = "@" + v[p + 11:-1]
|
||||||
|
self.putValue(v)
|
||||||
|
if self.isExpanded(iname):
|
||||||
|
self.put("children=[")
|
||||||
|
for child in dir(value):
|
||||||
|
if child == "__dict__":
|
||||||
|
continue
|
||||||
|
if child == "__doc__":
|
||||||
|
continue
|
||||||
|
if child == "__module__":
|
||||||
|
continue
|
||||||
|
attr = getattr(value, child)
|
||||||
|
if callable(attr):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
self.dumpValue(attr, child, "%s.%s" % (iname, child))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.put("],")
|
||||||
|
self.put("},")
|
||||||
|
|
||||||
|
|
||||||
|
def warn(self, msg):
|
||||||
|
self.putField("warning", msg)
|
||||||
|
|
||||||
|
def handleListModules(self):
|
||||||
|
self.put("modules=[");
|
||||||
|
for name in sys.modules:
|
||||||
|
self.put("{")
|
||||||
|
self.putName(name)
|
||||||
|
self.putValue(sys.modules[name])
|
||||||
|
self.put("},")
|
||||||
|
self.put("]")
|
||||||
|
#sys.stdout.flush()
|
||||||
|
|
||||||
|
def handleListSymbols(self, module):
|
||||||
|
#self.put("symbols=%s" % dir(sys.modules[module]))
|
||||||
|
self.put("symbols=[");
|
||||||
|
for name in sys.modules:
|
||||||
|
self.put("{")
|
||||||
|
self.putName(name)
|
||||||
|
#self.putValue(sys.modules[name])
|
||||||
|
self.put("},")
|
||||||
|
self.put("]")
|
||||||
|
#sys.stdout.flush()
|
||||||
|
|
||||||
|
def stackListFrames(self, args):
|
||||||
|
#isNativeMixed = int(args.get('nativeMixed', 0))
|
||||||
|
#result = 'stack={current-thread="%s"' % thread.GetThreadID()
|
||||||
|
result = 'stack={current-thread="%s"' % 1
|
||||||
|
result += ',frames=['
|
||||||
|
|
||||||
|
level = 0
|
||||||
|
for frame in inspect.stack():
|
||||||
|
l = [i for i in frame]
|
||||||
|
fileName = l[1]
|
||||||
|
(head, tail) = os.path.split(fileName)
|
||||||
|
if tail in ("pdbbridge.py", "bdb.py", "pdb.py", "cmd.py", "<stdin>"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
level += 1
|
||||||
|
result += '{'
|
||||||
|
result += 'a0="%s",' % l[0]
|
||||||
|
result += 'file="%s",' % fileName
|
||||||
|
result += 'line="%s",' % l[2]
|
||||||
|
result += 'a3="%s",' % l[3]
|
||||||
|
result += 'a4="%s",' % l[4]
|
||||||
|
result += 'a5="%s",' % l[5]
|
||||||
|
result += 'level="%s",' % level
|
||||||
|
result += '}'
|
||||||
|
|
||||||
|
result += ']'
|
||||||
|
#result += ',hasmore="%d"' % isLimited
|
||||||
|
#result += ',limit="%d"' % limit
|
||||||
|
result += '}'
|
||||||
|
self.report(result)
|
||||||
|
|
||||||
|
|
||||||
|
def report(self, stuff):
|
||||||
|
sys.stdout.write("@\n" + stuff + "@\n")
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
def qdebug(options = None,
|
def qdebug(options = None,
|
||||||
expanded = None,
|
expanded = None,
|
||||||
typeformats = None,
|
typeformats = None,
|
||||||
individualformats = None,
|
individualformats = None,
|
||||||
watchers = None):
|
watchers = None):
|
||||||
|
sys.stdout.write("\n(Pdb)\n")
|
||||||
class QDebug:
|
|
||||||
def __init__(self,
|
|
||||||
options = None,
|
|
||||||
expanded = None,
|
|
||||||
typeformats = None,
|
|
||||||
individualformats = None,
|
|
||||||
watchers = None):
|
|
||||||
self.options = options
|
|
||||||
self.expandedINames = expanded
|
|
||||||
self.typeformats = typeformats
|
|
||||||
self.individualformats = individualformats
|
|
||||||
self.watchers = watchers
|
|
||||||
self.buffer = ""
|
|
||||||
if self.options == "listmodules":
|
|
||||||
self.handleListModules()
|
|
||||||
elif self.options == "listsymbols":
|
|
||||||
self.handleListSymbols(expanded)
|
|
||||||
else:
|
|
||||||
self.handleListVars()
|
|
||||||
|
|
||||||
def put(self, value):
|
|
||||||
#sys.stdout.write(value)
|
|
||||||
self.buffer += value
|
|
||||||
|
|
||||||
def putField(self, name, value):
|
|
||||||
self.put('%s="%s",' % (name, value))
|
|
||||||
|
|
||||||
def putItemCount(self, count):
|
|
||||||
self.put('value="<%s items>",' % count)
|
|
||||||
|
|
||||||
def putEllipsis(self):
|
|
||||||
self.put('{name="<incomplete>",value="",type="",numchild="0"},')
|
|
||||||
|
|
||||||
def cleanType(self, type):
|
|
||||||
t = str(type)
|
|
||||||
if t.startswith("<type '") and t.endswith("'>"):
|
|
||||||
t = t[7:-2]
|
|
||||||
if t.startswith("<class '") and t.endswith("'>"):
|
|
||||||
t = t[8:-2]
|
|
||||||
return t
|
|
||||||
|
|
||||||
def putType(self, type, priority = 0):
|
|
||||||
self.putField("type", self.cleanType(type))
|
|
||||||
|
|
||||||
def putAddress(self, addr):
|
|
||||||
self.put('addr="%s",' % cleanAddress(addr))
|
|
||||||
|
|
||||||
def putNumChild(self, numchild):
|
|
||||||
self.put('numchild="%s",' % numchild)
|
|
||||||
|
|
||||||
def putValue(self, value, encoding = None, priority = 0):
|
|
||||||
self.putField("value", value)
|
|
||||||
|
|
||||||
def putName(self, name):
|
|
||||||
self.put('name="%s",' % name)
|
|
||||||
|
|
||||||
def isExpanded(self, iname):
|
|
||||||
#self.warn("IS EXPANDED: %s in %s" % (iname, self.expandedINames))
|
|
||||||
if iname.startswith("None"):
|
|
||||||
raise "Illegal iname '%s'" % iname
|
|
||||||
#self.warn(" --> %s" % (iname in self.expandedINames))
|
|
||||||
return iname in self.expandedINames
|
|
||||||
|
|
||||||
def isExpandedIName(self, iname):
|
|
||||||
return iname in self.expandedINames
|
|
||||||
|
|
||||||
def itemFormat(self, item):
|
|
||||||
format = self.formats.get(str(cleanAddress(item.value.address)))
|
|
||||||
if format is None:
|
|
||||||
format = self.typeformats.get(self.stripClassTag(str(item.value.type)))
|
|
||||||
return format
|
|
||||||
|
|
||||||
def dumpFrame(self, frame):
|
|
||||||
for var in frame.f_locals.keys():
|
|
||||||
if var == "__file__":
|
|
||||||
continue
|
|
||||||
#if var == "__name__":
|
|
||||||
# continue
|
|
||||||
if var == "__package__":
|
|
||||||
continue
|
|
||||||
if var == "qdebug":
|
|
||||||
continue
|
|
||||||
if var != '__builtins__':
|
|
||||||
value = frame.f_locals[var]
|
|
||||||
self.dumpValue(value, var, "local.%s" % var)
|
|
||||||
|
|
||||||
def dumpValue(self, value, name, iname):
|
|
||||||
t = type(value)
|
|
||||||
tt = self.cleanType(t)
|
|
||||||
if tt == "module" or tt == "function":
|
|
||||||
return
|
|
||||||
if str(value).startswith("<class '"):
|
|
||||||
return
|
|
||||||
# FIXME: Should we?
|
|
||||||
if str(value).startswith("<enum-item "):
|
|
||||||
return
|
|
||||||
self.put("{")
|
|
||||||
self.putField("iname", iname)
|
|
||||||
self.putName(name)
|
|
||||||
self.putType(tt)
|
|
||||||
if tt == "NoneType":
|
|
||||||
self.putValue("None")
|
|
||||||
self.putNumChild(0)
|
|
||||||
elif tt == "list" or tt == "tuple":
|
|
||||||
self.putItemCount(len(value))
|
|
||||||
#self.putValue(value)
|
|
||||||
self.put("children=[")
|
|
||||||
for i in xrange(len(value)):
|
|
||||||
self.dumpValue(value[i], str(i), "%s.%d" % (iname, i))
|
|
||||||
self.put("]")
|
|
||||||
elif tt == "str":
|
|
||||||
v = value
|
|
||||||
self.putValue(v.encode('hex'))
|
|
||||||
self.putField("valueencoded", 6)
|
|
||||||
self.putNumChild(0)
|
|
||||||
elif tt == "unicode":
|
|
||||||
v = value
|
|
||||||
self.putValue(v.encode('hex'))
|
|
||||||
self.putField("valueencoded", 6)
|
|
||||||
self.putNumChild(0)
|
|
||||||
elif tt == "buffer":
|
|
||||||
v = str(value)
|
|
||||||
self.putValue(v.encode('hex'))
|
|
||||||
self.putField("valueencoded", 6)
|
|
||||||
self.putNumChild(0)
|
|
||||||
elif tt == "xrange":
|
|
||||||
b = iter(value).next()
|
|
||||||
e = b + len(value)
|
|
||||||
self.putValue("(%d, %d)" % (b, e))
|
|
||||||
self.putNumChild(0)
|
|
||||||
elif tt == "dict":
|
|
||||||
self.putItemCount(len(value))
|
|
||||||
self.putField("childnumchild", 2)
|
|
||||||
self.put("children=[")
|
|
||||||
i = 0
|
|
||||||
for (k, v) in value.iteritems():
|
|
||||||
self.put("{")
|
|
||||||
self.putType(" ")
|
|
||||||
self.putValue("%s: %s" % (k, v))
|
|
||||||
if self.isExpanded(iname):
|
|
||||||
self.put("children=[")
|
|
||||||
self.dumpValue(k, "key", "%s.%d.k" % (iname, i))
|
|
||||||
self.dumpValue(v, "value", "%s.%d.v" % (iname, i))
|
|
||||||
self.put("]")
|
|
||||||
self.put("},")
|
|
||||||
i += 1
|
|
||||||
self.put("]")
|
|
||||||
elif tt == "class":
|
|
||||||
pass
|
|
||||||
elif tt == "module":
|
|
||||||
pass
|
|
||||||
elif tt == "function":
|
|
||||||
pass
|
|
||||||
elif str(value).startswith("<enum-item "):
|
|
||||||
# FIXME: Having enums always shown like this is not nice.
|
|
||||||
self.putValue(str(value)[11:-1])
|
|
||||||
self.putNumChild(0)
|
|
||||||
else:
|
|
||||||
v = str(value)
|
|
||||||
p = v.find(" object at ")
|
|
||||||
if p > 1:
|
|
||||||
v = "@" + v[p + 11:-1]
|
|
||||||
self.putValue(v)
|
|
||||||
if self.isExpanded(iname):
|
|
||||||
self.put("children=[")
|
|
||||||
for child in dir(value):
|
|
||||||
if child == "__dict__":
|
|
||||||
continue
|
|
||||||
if child == "__doc__":
|
|
||||||
continue
|
|
||||||
if child == "__module__":
|
|
||||||
continue
|
|
||||||
attr = getattr(value, child)
|
|
||||||
if callable(attr):
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
self.dumpValue(attr, child, "%s.%s" % (iname, child))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
self.put("],")
|
|
||||||
self.put("},")
|
|
||||||
|
|
||||||
|
|
||||||
def warn(self, msg):
|
|
||||||
self.putField("warning", msg)
|
|
||||||
|
|
||||||
def handleListVars(self):
|
|
||||||
# Trigger error to get a backtrace.
|
|
||||||
frame = None
|
|
||||||
#self.warn("frame: %s" % frame)
|
|
||||||
try:
|
|
||||||
raise ZeroDivisionError
|
|
||||||
except ZeroDivisionError:
|
|
||||||
frame = sys.exc_info()[2].tb_frame.f_back
|
|
||||||
|
|
||||||
limit = 30
|
|
||||||
n = 0
|
|
||||||
isActive = False
|
|
||||||
while frame is not None and n < limit:
|
|
||||||
#self.warn("frame: %s" % frame.f_locals.keys())
|
|
||||||
lineno = frame.f_lineno
|
|
||||||
code = frame.f_code
|
|
||||||
filename = code.co_filename
|
|
||||||
name = code.co_name
|
|
||||||
if isActive:
|
|
||||||
linecache.checkcache(filename)
|
|
||||||
line = linecache.getline(filename, lineno, frame.f_globals)
|
|
||||||
self.dumpFrame(frame)
|
|
||||||
if name == "<module>":
|
|
||||||
isActive = False
|
|
||||||
if name == "trace_dispatch":
|
|
||||||
isActive = True
|
|
||||||
frame = frame.f_back
|
|
||||||
n = n + 1
|
|
||||||
#sys.stdout.flush()
|
|
||||||
|
|
||||||
def handleListModules(self):
|
|
||||||
self.put("modules=[");
|
|
||||||
for name in sys.modules:
|
|
||||||
self.put("{")
|
|
||||||
self.putName(name)
|
|
||||||
self.putValue(sys.modules[name])
|
|
||||||
self.put("},")
|
|
||||||
self.put("]")
|
|
||||||
#sys.stdout.flush()
|
|
||||||
|
|
||||||
def handleListSymbols(self, module):
|
|
||||||
#self.put("symbols=%s" % dir(sys.modules[module]))
|
|
||||||
self.put("symbols=[");
|
|
||||||
for name in sys.modules:
|
|
||||||
self.put("{")
|
|
||||||
self.putName(name)
|
|
||||||
#self.putValue(sys.modules[name])
|
|
||||||
self.put("},")
|
|
||||||
self.put("]")
|
|
||||||
#sys.stdout.flush()
|
|
||||||
|
|
||||||
d = QDebug(options, expanded, typeformats, individualformats, watchers)
|
|
||||||
#print d.buffer
|
|
||||||
sys.stdout.write(d.buffer)
|
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
theDumper = Dumper()
|
||||||
|
@@ -132,6 +132,14 @@ void PdbEngine::postCommand(const QByteArray &command, DebuggerCommand::Callback
|
|||||||
m_pdbProc.write(cmd.function + '\n');
|
m_pdbProc.write(cmd.function + '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PdbEngine::runCommand(const DebuggerCommand &cmd)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_pdbProc.state() == QProcess::Running, notifyEngineIll());
|
||||||
|
QByteArray command = "theDumper." + cmd.function + "({" + cmd.args + "})";
|
||||||
|
showMessage(_(command), LogInput);
|
||||||
|
m_pdbProc.write(command + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
void PdbEngine::shutdownInferior()
|
void PdbEngine::shutdownInferior()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
|
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
|
||||||
@@ -361,6 +369,8 @@ void PdbEngine::handleBreakInsert(const DebuggerResponse &response, Breakpoint b
|
|||||||
br.id = BreakpointResponseId(bpnr);
|
br.id = BreakpointResponseId(bpnr);
|
||||||
br.fileName = _(file);
|
br.fileName = _(file);
|
||||||
br.lineNumber = line.toInt();
|
br.lineNumber = line.toInt();
|
||||||
|
if (!bp.isValid())
|
||||||
|
bp = breakHandler()->findBreakpointByFileAndLine(br.fileName, br.lineNumber, false);
|
||||||
bp.setResponse(br);
|
bp.setResponse(br);
|
||||||
QTC_CHECK(!bp.needsChange());
|
QTC_CHECK(!bp.needsChange());
|
||||||
bp.notifyBreakpointInsertOk();
|
bp.notifyBreakpointInsertOk();
|
||||||
@@ -444,7 +454,6 @@ void PdbEngine::handleListSymbols(const DebuggerResponse &response, const QStrin
|
|||||||
|
|
||||||
static WatchData m_toolTip;
|
static WatchData m_toolTip;
|
||||||
static QPoint m_toolTipPos;
|
static QPoint m_toolTipPos;
|
||||||
static QHash<QString, WatchData> m_toolTipCache;
|
|
||||||
|
|
||||||
bool PdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget,
|
bool PdbEngine::setToolTipExpression(TextEditor::TextEditorWidget *editorWidget,
|
||||||
const DebuggerToolTipContext &ctx)
|
const DebuggerToolTipContext &ctx)
|
||||||
@@ -626,19 +635,71 @@ void PdbEngine::handleOutput(const QByteArray &data)
|
|||||||
|
|
||||||
void PdbEngine::handleOutput2(const QByteArray &data)
|
void PdbEngine::handleOutput2(const QByteArray &data)
|
||||||
{
|
{
|
||||||
DebuggerResponse response;
|
QByteArray lineContext;
|
||||||
response.logStreamOutput = data;
|
foreach (QByteArray line, data.split('\n')) {
|
||||||
showMessage(_(data));
|
// line = line.trimmed();
|
||||||
QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return);
|
|
||||||
DebuggerCommand cmd = m_commands.dequeue();
|
DebuggerResponse response;
|
||||||
qDebug() << "DEQUE: " << cmd.function;
|
response.logStreamOutput = line;
|
||||||
if (cmd.callback) {
|
response.data.fromString(line);
|
||||||
//qDebug() << "EXECUTING CALLBACK " << cmd.callbackName
|
showMessage(_("LINE: " + line));
|
||||||
// << " RESPONSE: " << response.data;
|
|
||||||
cmd.callback(response);
|
if (line.startsWith("stack={")) {
|
||||||
} else {
|
refreshStack(response.data);
|
||||||
qDebug() << "NO CALLBACK FOR RESPONSE: " << response.logStreamOutput;
|
continue;
|
||||||
|
}
|
||||||
|
if (line.startsWith("data={")) {
|
||||||
|
refreshLocals(response.data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line.startsWith("Breakpoint")) {
|
||||||
|
handleBreakInsert(response, Breakpoint());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("> /")) {
|
||||||
|
lineContext = line;
|
||||||
|
int pos1 = line.indexOf('(');
|
||||||
|
int pos2 = line.indexOf(')', pos1);
|
||||||
|
if (pos1 != -1 && pos2 != -1) {
|
||||||
|
int lineNumber = line.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
|
||||||
|
QByteArray fileName = line.mid(2, pos1 - 2);
|
||||||
|
qDebug() << " " << pos1 << pos2 << lineNumber << fileName
|
||||||
|
<< line.mid(pos1 + 1, pos2 - pos1 - 1);
|
||||||
|
StackFrame frame;
|
||||||
|
frame.file = _(fileName);
|
||||||
|
frame.line = lineNumber;
|
||||||
|
if (state() == InferiorRunOk) {
|
||||||
|
showMessage(QString::fromLatin1("STOPPED AT: %1:%2").arg(frame.file).arg(frame.line));
|
||||||
|
gotoLocation(frame);
|
||||||
|
notifyInferiorSpontaneousStop();
|
||||||
|
updateAll();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("-> ")) {
|
||||||
|
// Current line
|
||||||
|
}
|
||||||
|
|
||||||
|
showMessage(_(" #### ... UNHANDLED"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DebuggerResponse response;
|
||||||
|
// response.logStreamOutput = data;
|
||||||
|
// showMessage(_(data));
|
||||||
|
// QTC_ASSERT(!m_commands.isEmpty(), qDebug() << "RESPONSE: " << data; return);
|
||||||
|
// DebuggerCommand cmd = m_commands.dequeue();
|
||||||
|
// qDebug() << "DEQUE: " << cmd.function;
|
||||||
|
// if (cmd.callback) {
|
||||||
|
// //qDebug() << "EXECUTING CALLBACK " << cmd.callbackName
|
||||||
|
// // << " RESPONSE: " << response.data;
|
||||||
|
// cmd.callback(response);
|
||||||
|
// } else {
|
||||||
|
// qDebug() << "NO CALLBACK FOR RESPONSE: " << response.logStreamOutput;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
void PdbEngine::handleResponse(const QByteArray &response0)
|
void PdbEngine::handleResponse(const QByteArray &response0)
|
||||||
@@ -653,28 +714,65 @@ void PdbEngine::handleResponse(const QByteArray &response0)
|
|||||||
qDebug() << "SKIPPING '--Return--' MARKER";
|
qDebug() << "SKIPPING '--Return--' MARKER";
|
||||||
response = response.mid(11);
|
response = response.mid(11);
|
||||||
}
|
}
|
||||||
if (response.startsWith("> ")) {
|
|
||||||
int pos1 = response.indexOf('(');
|
|
||||||
int pos2 = response.indexOf(')', pos1);
|
|
||||||
if (pos1 != -1 && pos2 != -1) {
|
|
||||||
int lineNumber = response.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
|
|
||||||
QByteArray fileName = response.mid(2, pos1 - 2);
|
|
||||||
qDebug() << " " << pos1 << pos2 << lineNumber << fileName
|
|
||||||
<< response.mid(pos1 + 1, pos2 - pos1 - 1);
|
|
||||||
StackFrame frame;
|
|
||||||
frame.file = _(fileName);
|
|
||||||
frame.line = lineNumber;
|
|
||||||
if (frame.line > 0 && QFileInfo(frame.file).exists()) {
|
|
||||||
gotoLocation(frame);
|
|
||||||
notifyInferiorSpontaneousStop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qDebug() << "COULD NOT PARSE RESPONSE: '" << response << "'";
|
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void PdbEngine::refreshLocals(const GdbMi &vars)
|
||||||
|
{
|
||||||
|
//const bool partial = response.cookie.toBool();
|
||||||
|
WatchHandler *handler = watchHandler();
|
||||||
|
handler->resetValueCache();
|
||||||
|
|
||||||
|
QSet<QByteArray> toDelete;
|
||||||
|
foreach (WatchItem *item, handler->model()->treeLevelItems<WatchItem *>(2))
|
||||||
|
toDelete.insert(item->d.iname);
|
||||||
|
|
||||||
|
foreach (const GdbMi &child, vars.children()) {
|
||||||
|
WatchItem *item = new WatchItem(child);
|
||||||
|
handler->insertItem(item);
|
||||||
|
toDelete.remove(item->d.iname);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->purgeOutdatedItems(toDelete);
|
||||||
|
|
||||||
|
DebuggerToolTipManager::updateEngine(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PdbEngine::refreshStack(const GdbMi &stack)
|
||||||
|
{
|
||||||
|
StackHandler *handler = stackHandler();
|
||||||
|
StackFrames frames;
|
||||||
|
foreach (const GdbMi &item, stack["frames"].children()) {
|
||||||
|
StackFrame frame;
|
||||||
|
frame.level = item["level"].toInt();
|
||||||
|
frame.file = item["file"].toUtf8();
|
||||||
|
frame.function = item["func"].toUtf8();
|
||||||
|
frame.from = item["func"].toUtf8();
|
||||||
|
frame.line = item["line"].toInt();
|
||||||
|
frame.address = item["addr"].toAddress();
|
||||||
|
GdbMi usable = item["usable"];
|
||||||
|
if (usable.isValid())
|
||||||
|
frame.usable = usable.data().toInt();
|
||||||
|
else
|
||||||
|
frame.usable = QFileInfo(frame.file).isReadable();
|
||||||
|
if (item["language"].data() == "js"
|
||||||
|
|| frame.file.endsWith(QLatin1String(".js"))
|
||||||
|
|| frame.file.endsWith(QLatin1String(".qml"))) {
|
||||||
|
frame.language = QmlLanguage;
|
||||||
|
frame.fixQmlFrame(startParameters());
|
||||||
|
}
|
||||||
|
frames.append(frame);
|
||||||
|
}
|
||||||
|
bool canExpand = stack["hasmore"].toInt();
|
||||||
|
//action(ExpandStack)->setEnabled(canExpand);
|
||||||
|
handler->setFrames(frames, canExpand);
|
||||||
|
|
||||||
|
int index = stackHandler()->firstUsableIndex();
|
||||||
|
handler->setCurrentIndex(index);
|
||||||
|
if (index >= 0 && index < handler->stackSize())
|
||||||
|
gotoLocation(handler->frameAt(index));
|
||||||
|
}
|
||||||
|
|
||||||
void PdbEngine::handleFirstCommand(const DebuggerResponse &response)
|
void PdbEngine::handleFirstCommand(const DebuggerResponse &response)
|
||||||
{
|
{
|
||||||
Q_UNUSED(response);
|
Q_UNUSED(response);
|
||||||
@@ -689,100 +787,50 @@ void PdbEngine::handleUpdateAll(const DebuggerResponse &response)
|
|||||||
|
|
||||||
void PdbEngine::updateAll()
|
void PdbEngine::updateAll()
|
||||||
{
|
{
|
||||||
postCommand("bt", CB(handleBacktrace));
|
postCommand("dir()");
|
||||||
//updateLocals();
|
postCommand("theDumper.stackListFrames({})");
|
||||||
|
updateLocals();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PdbEngine::updateLocals()
|
void PdbEngine::updateLocals()
|
||||||
{
|
{
|
||||||
QByteArray watchers;
|
DebuggerCommand cmd("updateData");
|
||||||
//if (!m_toolTipExpression.isEmpty())
|
cmd.arg("nativeMixed", isNativeMixedActive());
|
||||||
// watchers += m_toolTipExpression.toLatin1()
|
watchHandler()->appendFormatRequests(&cmd);
|
||||||
// + '#' + tooltipINameForExpression(m_toolTipExpression.toLatin1());
|
|
||||||
|
|
||||||
WatchHandler *handler = watchHandler();
|
const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
|
||||||
QHash<QByteArray, int> watcherNames = handler->watcherNames();
|
cmd.arg("passexceptions", alwaysVerbose);
|
||||||
QHashIterator<QByteArray, int> it(watcherNames);
|
cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
|
||||||
|
// cmd.arg("partial", params.tryPartial);
|
||||||
|
|
||||||
|
cmd.beginList("watchers");
|
||||||
|
|
||||||
|
// Watchers
|
||||||
|
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
it.next();
|
it.next();
|
||||||
if (!watchers.isEmpty())
|
cmd.beginGroup();
|
||||||
watchers += "##";
|
cmd.arg("iname", "watch." + QByteArray::number(it.value()));
|
||||||
watchers += it.key() + "#watch." + QByteArray::number(it.value());
|
cmd.arg("exp", it.key().toHex());
|
||||||
|
cmd.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray options;
|
// Tooltips
|
||||||
if (boolSetting(UseDebuggingHelpers))
|
DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
|
||||||
options += "fancy,";
|
foreach (const DebuggerToolTipContext &p, toolTips) {
|
||||||
if (boolSetting(AutoDerefPointers))
|
cmd.beginGroup();
|
||||||
options += "autoderef,";
|
cmd.arg("iname", p.iname);
|
||||||
if (options.isEmpty())
|
cmd.arg("exp", p.expression.toLatin1().toHex());
|
||||||
options += "defaults,";
|
cmd.endGroup();
|
||||||
options.chop(1);
|
|
||||||
|
|
||||||
postCommand("qdebug('" + options + "','"
|
|
||||||
// + handler->expansionRequests() + "','"
|
|
||||||
+ handler->typeFormatRequests() + "','"
|
|
||||||
+ handler->individualFormatRequests() + "','"
|
|
||||||
+ watchers.toHex() + "')", CB(handleListLocals));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PdbEngine::handleBacktrace(const DebuggerResponse &response)
|
|
||||||
{
|
|
||||||
//qDebug() << " BACKTRACE: '" << response.data << "'";
|
|
||||||
// " /usr/lib/python2.6/bdb.py(368)run()"
|
|
||||||
// "-> exec cmd in globals, locals"
|
|
||||||
// " <string>(1)<module>()"
|
|
||||||
// " /python/math.py(19)<module>()"
|
|
||||||
// "-> main()"
|
|
||||||
// " /python/math.py(14)main()"
|
|
||||||
// "-> print cube(3)"
|
|
||||||
// " /python/math.py(7)cube()"
|
|
||||||
// "-> x = square(a)"
|
|
||||||
// "> /python/math.py(2)square()"
|
|
||||||
// "-> def square(a):"
|
|
||||||
|
|
||||||
// Populate stack view.
|
|
||||||
StackFrames stackFrames;
|
|
||||||
int level = 0;
|
|
||||||
int currentIndex = -1;
|
|
||||||
foreach (const QByteArray &line, response.logStreamOutput.split('\n')) {
|
|
||||||
//qDebug() << " LINE: '" << line << "'";
|
|
||||||
if (line.startsWith("> ") || line.startsWith(" ")) {
|
|
||||||
int pos1 = line.indexOf('(');
|
|
||||||
int pos2 = line.indexOf(')', pos1);
|
|
||||||
if (pos1 != -1 && pos2 != -1) {
|
|
||||||
int lineNumber = line.mid(pos1 + 1, pos2 - pos1 - 1).toInt();
|
|
||||||
QByteArray fileName = line.mid(2, pos1 - 2);
|
|
||||||
//qDebug() << " " << pos1 << pos2 << lineNumber << fileName
|
|
||||||
// << line.mid(pos1 + 1, pos2 - pos1 - 1);
|
|
||||||
StackFrame frame;
|
|
||||||
frame.file = _(fileName);
|
|
||||||
frame.line = lineNumber;
|
|
||||||
frame.function = _(line.mid(pos2 + 1));
|
|
||||||
frame.usable = QFileInfo(frame.file).isReadable();
|
|
||||||
if (frame.line > 0 && QFileInfo::exists(frame.file)) {
|
|
||||||
if (line.startsWith("> "))
|
|
||||||
currentIndex = level;
|
|
||||||
frame.level = level;
|
|
||||||
stackFrames.prepend(frame);
|
|
||||||
++level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const int frameCount = stackFrames.size();
|
|
||||||
for (int i = 0; i != frameCount; ++i)
|
|
||||||
stackFrames[i].level = frameCount - stackFrames[i].level - 1;
|
|
||||||
stackHandler()->setFrames(stackFrames);
|
|
||||||
|
|
||||||
// Select current frame.
|
|
||||||
if (currentIndex != -1) {
|
|
||||||
currentIndex = frameCount - currentIndex - 1;
|
|
||||||
stackHandler()->setCurrentIndex(currentIndex);
|
|
||||||
gotoLocation(stackFrames.at(currentIndex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLocals();
|
cmd.endList();
|
||||||
|
|
||||||
|
//cmd.arg("resultvarname", m_resultVarName);
|
||||||
|
//m_lastDebuggableCommand = cmd;
|
||||||
|
//m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");
|
||||||
|
|
||||||
|
runCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PdbEngine::handleListLocals(const DebuggerResponse &response)
|
void PdbEngine::handleListLocals(const DebuggerResponse &response)
|
||||||
|
@@ -54,6 +54,10 @@ public:
|
|||||||
explicit PdbEngine(const DebuggerStartParameters &startParameters);
|
explicit PdbEngine(const DebuggerStartParameters &startParameters);
|
||||||
~PdbEngine();
|
~PdbEngine();
|
||||||
|
|
||||||
|
void refreshStack(const GdbMi &stack);
|
||||||
|
void runCommand(const DebuggerCommand &cmd);
|
||||||
|
void refreshLocals(const GdbMi &vars);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// DebuggerEngine implementation
|
// DebuggerEngine implementation
|
||||||
void executeStep();
|
void executeStep();
|
||||||
@@ -122,7 +126,6 @@ private:
|
|||||||
void handleFirstCommand(const DebuggerResponse &response);
|
void handleFirstCommand(const DebuggerResponse &response);
|
||||||
void handleExecuteDebuggerCommand(const DebuggerResponse &response);
|
void handleExecuteDebuggerCommand(const DebuggerResponse &response);
|
||||||
void handleStop(const DebuggerResponse &response);
|
void handleStop(const DebuggerResponse &response);
|
||||||
void handleBacktrace(const DebuggerResponse &response);
|
|
||||||
void handleListLocals(const DebuggerResponse &response);
|
void handleListLocals(const DebuggerResponse &response);
|
||||||
void handleListModules(const DebuggerResponse &response);
|
void handleListModules(const DebuggerResponse &response);
|
||||||
void handleListSymbols(const DebuggerResponse &response, const QString &moduleName);
|
void handleListSymbols(const DebuggerResponse &response, const QString &moduleName);
|
||||||
|
Reference in New Issue
Block a user