Debugger: Convert bb extension to use runCommand

Change-Id: I528c51d2b02dccd91429778ef8c940fe5565345f
Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
hjk
2015-02-11 17:51:15 +01:00
parent d9408156d1
commit 9df463da84
4 changed files with 104 additions and 166 deletions

View File

@@ -208,22 +208,6 @@ def stripTypedefs(typeobj):
return typeobj
#######################################################################
#
# Frame Command
#
#######################################################################
def bb(args):
try:
print(theDumper.run(args))
except:
import traceback
traceback.print_exc()
registerCommand("bb", bb)
#######################################################################
#
# The Dumper Class
@@ -236,7 +220,7 @@ class Dumper(DumperBase):
def __init__(self):
DumperBase.__init__(self)
# These values will be kept between calls to 'run'.
# These values will be kept between calls to 'showData'.
self.isGdb = True
self.childEventAddress = None
self.typesReported = {}
@@ -256,60 +240,40 @@ class Dumper(DumperBase):
self.currentValue = ReportItem()
self.currentType = ReportItem()
self.currentAddress = None
self.typeformats = {}
self.formats = {}
self.useDynamicType = True
self.expandedINames = {}
self.qmlcontext = ""
# The guess does not need to be updated during a run()
# The guess does not need to be updated during a showData()
# as the result is fixed during that time (ignoring "active"
# dumpers causing loading of shared objects etc).
self.currentQtNamespaceGuess = None
self.watchers = ""
self.resultVarName = ""
self.varList = []
self.options = []
self.varList = args.get("vars", [])
self.resultVarName = args.get("resultvarname", "")
self.expandedINames = set(args.get("expanded", []))
self.stringCutOff = int(args.get("stringcutoff", 10000))
self.displayStringLimit = int(args.get("displaystringlimit", 10000))
for arg in args.split(' '):
pos = arg.find(":") + 1
if arg.startswith("options:"):
self.options = arg[pos:].split(",")
elif arg.startswith("vars:"):
if len(arg[pos:]) > 0:
self.varList = arg[pos:].split(",")
elif arg.startswith("resultvarname:"):
self.resultVarName = arg[pos:]
elif arg.startswith("expanded:"):
self.expandedINames = set(arg[pos:].split(","))
elif arg.startswith("stringcutoff:"):
self.stringCutOff = int(arg[pos:])
elif arg.startswith("displaystringlimit:"):
self.displayStringLimit = int(arg[pos:])
elif arg.startswith("typeformats:"):
for f in arg[pos:].split(","):
pos = f.find("=")
if pos != -1:
typeName = self.hexdecode(f[0:pos])
self.typeformats[typeName] = int(f[pos+1:])
elif arg.startswith("formats:"):
for f in arg[pos:].split(","):
pos = f.find("=")
if pos != -1:
self.formats[f[0:pos]] = int(f[pos+1:])
elif arg.startswith("watchers:"):
self.watchers = self.hexdecode(arg[pos:])
elif arg.startswith("qmlcontext:"):
self.qmlcontext = int(arg[pos:], 0)
self.typeformats = {}
for f in args.get("typeformats", "").split(","):
pos = f.find("=")
if pos != -1:
typeName = self.hexdecode(f[0:pos])
self.typeformats[typeName] = int(f[pos+1:])
self.useDynamicType = "dyntype" in self.options
self.useFancy = "fancy" in self.options
self.forceQtNamespace = "forcens" in self.options
self.passExceptions = "pe" in self.options
self.nativeMixed = "nativemixed" in self.options
self.autoDerefPointers = "autoderef" in self.options
self.partialUpdate = "partial" in self.options
self.formats = {}
for f in args.get("formats", "").split(","):
pos = f.find("=")
if pos != -1:
self.formats[f[0:pos]] = int(f[pos+1:])
self.watchers = args.get("watchers", {})
self.qmlcontext = int(args.get("qmlcontext", "0"))
self.useDynamicType = int(args.get("dyntype", "0"))
self.useFancy = int(args.get("fancy", "0"))
self.forceQtNamespace = int(args.get("forcens", "0"))
self.passExceptions = int(args.get("passExceptions", "0"))
self.nativeMixed = int(args.get("nativemixed", "0"))
self.autoDerefPointers = int(args.get("autoderef", "0"))
self.partialUpdate = int(args.get("partial", "0"))
self.fallbackQtVersion = 0x50200
#warn("NAMESPACE: '%s'" % self.qtNamespace())
#warn("VARIABLES: %s" % self.varList)
@@ -319,10 +283,10 @@ class Dumper(DumperBase):
def handleWatches(self):
with OutputSafer(self):
if len(self.watchers) > 0:
for watcher in self.watchers.split("##"):
(exp, iname) = watcher.split("#")
self.handleWatch(exp, exp, iname)
for watcher in self.watchers:
iname = watcher['iname']
exp = self.hexdecode(watcher['exp'])
self.handleWatch(exp, exp, iname)
def listOfLocals(self):
frame = gdb.selected_frame()
@@ -405,7 +369,7 @@ class Dumper(DumperBase):
return items
def run(self, args):
def showData(self, args):
self.prepare(args)
#
@@ -481,14 +445,13 @@ class Dumper(DumperBase):
self.output.append(']')
self.typesToReport = {}
if "forcens" in self.options:
if self.forceQtNamespace:
self.qtNamepaceToReport = self.qtNamespace()
if self.qtNamespaceToReport:
self.output.append(',qtnamespace="%s"' % self.qtNamespaceToReport)
self.qtNamespaceToReport = None
return "".join(self.output)
print(''.join(self.output))
def enterSubItem(self, item):
if not item.iname:
@@ -1619,8 +1582,11 @@ class Dumper(DumperBase):
if limit <= 0:
limit = 10000
options = args['options']
opts = {}
if options == "nativemixed":
opts["nativemixed"] = 1
self.prepare("options:" + options + ",pe")
self.prepare(opts)
self.output = []
frame = gdb.newest_frame()
@@ -1699,6 +1665,21 @@ class Dumper(DumperBase):
matplotQuit()
gdb.execute("quit")
def profile1(self, args):
"""Internal profiling"""
import tempfile
import cProfile
tempDir = tempfile.gettempdir() + "/bbprof"
cProfile.run('theDumper.showData(%s)' % args, tempDir)
import pstats
pstats.Stats(tempDir).sort_stats('time').print_stats()
def profile2(self, args):
import timeit
print(timeit.repeat('theDumper.showData(%s)' % args,
'from __main__ import theDumper', number=10))
class CliDumper(Dumper):
def __init__(self):
@@ -1788,7 +1769,7 @@ class CliDumper(Dumper):
def putAddressRange(self, base, step):
return True
def run(self, args):
def showData(self, args):
arglist = args.split(' ')
name = ''
if len(arglist) >= 1:
@@ -1797,7 +1778,12 @@ class CliDumper(Dumper):
if len(arglist) >= 2:
for sub in arglist[1].split(','):
allexpanded.append(name + '.' + sub)
self.prepare("options:fancy,pe,autoderef expanded:" + ','.join(allexpanded))
pars = {}
pars['fancy': 1]
pars['passException': 1]
pars['autoderef': 1]
pars['expanded': allexpanded]
self.prepare(pars)
self.output = name + ' = '
frame = gdb.selected_frame()
value = frame.read_var(name)
@@ -1805,12 +1791,6 @@ class CliDumper(Dumper):
self.putItem(value)
return self.output
def pp(args):
return theDumper.run(args)
registerCommand("pp", pp)
# Global instance.
if gdb.parameter('height') is None:
theDumper = Dumper()
@@ -1818,40 +1798,7 @@ else:
import codecs
theDumper = CliDumper()
#######################################################################
#
# Internal profiling
#
#######################################################################
def p1(args):
import tempfile
import cProfile
tempDir = tempfile.gettempdir() + "/bbprof"
cProfile.run('bb("%s")' % args, tempDir)
import pstats
pstats.Stats(tempDir).sort_stats('time').print_stats()
return ""
registerCommand("p1", p1)
def p2(args):
import timeit
return timeit.repeat('bb("%s")' % args,
'from __main__ import bb', number=10)
registerCommand("p2", p2)
def p3(args):
eval(args)
def p3(args):
import timeit
return timeit.repeat('p3("%s")' % args, 'from __main__ import p3', number=10000)
registerCommand("p3", p3)
#######################################################################
######################################################################
#
# ThreadNames Command
#

View File

@@ -4723,7 +4723,7 @@ QByteArray GdbEngine::dotEscape(QByteArray str)
void GdbEngine::debugLastCommand()
{
postCommand(m_lastDebuggableCommand, Discardable);
runCommand(m_lastDebuggableCommand);
}
//
@@ -4761,73 +4761,59 @@ void GdbEngine::updateLocalsPython(const UpdateParameters &params)
m_processedNames.clear();
WatchHandler *handler = watchHandler();
QByteArray expanded = "expanded:" + handler->expansionRequests() + ' ';
expanded += "typeformats:" + handler->typeFormatRequests() + ' ';
expanded += "formats:" + handler->individualFormatRequests();
QByteArray cutOff = " stringcutoff:"
+ action(MaximalStringLength)->value().toByteArray()
+ " displaystringlimit:"
+ action(DisplayStringLimit)->value().toByteArray();
DebuggerCommand cmd("showData");
cmd.arg("expanded", handler->expansionRequests());
cmd.arg("typeformats", handler->typeFormatRequests());
cmd.arg("formats", handler->individualFormatRequests());
cmd.arg("stringcutoff", action(MaximalStringLength)->value().toByteArray());
cmd.arg("displaystringlimit", action(DisplayStringLimit)->value().toByteArray());
// Re-create tooltip items that are not filters on existing local variables in
// the tooltip model.
QByteArray watchers;
cmd.beginList("watchers");
DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
foreach (const DebuggerToolTipContext &p, toolTips) {
if (!watchers.isEmpty())
watchers += "##";
watchers += p.expression.toLatin1();
watchers += '#';
watchers += p.iname;
cmd.beginGroup();
cmd.arg("iname", p.iname);
cmd.arg("exp", p.expression.toLatin1().toHex());
cmd.endGroup();
}
QHash<QByteArray, int> watcherNames = handler->watcherNames();
QHashIterator<QByteArray, int> it(watcherNames);
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
while (it.hasNext()) {
it.next();
if (!watchers.isEmpty())
watchers += "##";
watchers += it.key() + "#watch." + QByteArray::number(it.value());
cmd.beginGroup();
cmd.arg("iname", "watch." + QByteArray::number(it.value()));
cmd.arg("exp", it.key().toHex());
cmd.endGroup();
}
cmd.endList();
const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
QByteArray options;
if (alwaysVerbose)
options += "pe,";
if (boolSetting(UseDebuggingHelpers))
options += "fancy,";
if (boolSetting(AutoDerefPointers))
options += "autoderef,";
if (boolSetting(UseDynamicType))
options += "dyntype,";
if (isNativeMixedActive())
options += "nativemixed,";
if (options.isEmpty())
options += "defaults,";
if (params.tryPartial)
options += "partial,";
options.chop(1);
QByteArray context;
cmd.arg("passExceptions", alwaysVerbose);
cmd.arg("fancy", boolSetting(UseDebuggingHelpers));
cmd.arg("autoderef", boolSetting(AutoDerefPointers));
cmd.arg("dyntype", boolSetting(UseDynamicType));
cmd.arg("nativemixed", isNativeMixedActive());
cmd.arg("partial", params.tryPartial);
if (isNativeMixedActive()) {
StackFrame frame = stackHandler()->currentFrame();
if (frame.language == QmlLanguage)
context += " qmlcontext:0x" + QByteArray::number(frame.address, 16);
cmd.arg("qmlcontext", "0x" + QByteArray::number(frame.address, 16));
}
QByteArray resultVar;
if (!m_resultVarName.isEmpty())
resultVar = "resultvarname:" + m_resultVarName + ' ';
cmd.arg("resultvarname", m_resultVarName);
cmd.arg("vars", params.varList);
cmd.flags = Discardable;
cmd.callback = [this, params](const DebuggerResponse &r) { handleStackFramePython(r, params.tryPartial); };
runCommand(cmd);
m_lastDebuggableCommand =
"bb options:pe," + options + " vars:" + params.varList + ' '
+ expanded + " watchers:" + watchers.toHex() + cutOff + context;
postCommand("bb options:" + options + " vars:" + params.varList + ' '
+ resultVar + expanded + " watchers:" + watchers.toHex() + cutOff + context,
Discardable,
[this, params](const DebuggerResponse &r) { handleStackFramePython(r, params.tryPartial); });
cmd.arg("passExceptions", true);
m_lastDebuggableCommand = cmd;
}
void GdbEngine::handleStackFramePython(const DebuggerResponse &response, bool partial)

View File

@@ -486,7 +486,7 @@ protected:
static QByteArray dotEscape(QByteArray str);
void debugLastCommand();
QByteArray m_lastDebuggableCommand;
DebuggerCommand m_lastDebuggableCommand;
protected:
virtual void write(const QByteArray &data);

View File

@@ -1204,10 +1204,14 @@ void tst_Dumpers::dumper()
}
QByteArray expanded;
QByteArray expandedq;
foreach (const QByteArray &iname, expandedINames) {
if (!expanded.isEmpty())
if (!expanded.isEmpty()) {
expanded.append(',');
expandedq.append(',');
}
expanded += iname;
expandedq += '\'' + iname + '\'';
}
QByteArray exe = m_debuggerBinary;
@@ -1238,7 +1242,8 @@ void tst_Dumpers::dumper()
"python from gdbbridge import *\n"
"python theDumper.setupDumper()\n"
"run " + nograb + "\n"
"bb options:fancy,forcens,autoderef,dyntype,pe vars: expanded:" + expanded + " typeformats:\n";
"python theDumper.showData({'fancy':1,'forcens':1,'autoderef':1,"
"'dyntype':1,'passExceptions':1,'expanded':[" + expandedq + "]})\n";
cmds += "quit\n";