forked from qt-creator/qt-creator
Debugger: Convert bb extension to use runCommand
Change-Id: I528c51d2b02dccd91429778ef8c940fe5565345f Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
@@ -208,22 +208,6 @@ def stripTypedefs(typeobj):
|
|||||||
return 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
|
# The Dumper Class
|
||||||
@@ -236,7 +220,7 @@ class Dumper(DumperBase):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
DumperBase.__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.isGdb = True
|
||||||
self.childEventAddress = None
|
self.childEventAddress = None
|
||||||
self.typesReported = {}
|
self.typesReported = {}
|
||||||
@@ -256,60 +240,40 @@ class Dumper(DumperBase):
|
|||||||
self.currentValue = ReportItem()
|
self.currentValue = ReportItem()
|
||||||
self.currentType = ReportItem()
|
self.currentType = ReportItem()
|
||||||
self.currentAddress = None
|
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"
|
# as the result is fixed during that time (ignoring "active"
|
||||||
# dumpers causing loading of shared objects etc).
|
# dumpers causing loading of shared objects etc).
|
||||||
self.currentQtNamespaceGuess = None
|
self.currentQtNamespaceGuess = None
|
||||||
|
|
||||||
self.watchers = ""
|
self.varList = args.get("vars", [])
|
||||||
self.resultVarName = ""
|
self.resultVarName = args.get("resultvarname", "")
|
||||||
self.varList = []
|
self.expandedINames = set(args.get("expanded", []))
|
||||||
self.options = []
|
self.stringCutOff = int(args.get("stringcutoff", 10000))
|
||||||
|
self.displayStringLimit = int(args.get("displaystringlimit", 10000))
|
||||||
|
|
||||||
for arg in args.split(' '):
|
self.typeformats = {}
|
||||||
pos = arg.find(":") + 1
|
for f in args.get("typeformats", "").split(","):
|
||||||
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("=")
|
pos = f.find("=")
|
||||||
if pos != -1:
|
if pos != -1:
|
||||||
typeName = self.hexdecode(f[0:pos])
|
typeName = self.hexdecode(f[0:pos])
|
||||||
self.typeformats[typeName] = int(f[pos+1:])
|
self.typeformats[typeName] = int(f[pos+1:])
|
||||||
elif arg.startswith("formats:"):
|
|
||||||
for f in arg[pos:].split(","):
|
self.formats = {}
|
||||||
|
for f in args.get("formats", "").split(","):
|
||||||
pos = f.find("=")
|
pos = f.find("=")
|
||||||
if pos != -1:
|
if pos != -1:
|
||||||
self.formats[f[0:pos]] = int(f[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.useDynamicType = "dyntype" in self.options
|
self.watchers = args.get("watchers", {})
|
||||||
self.useFancy = "fancy" in self.options
|
self.qmlcontext = int(args.get("qmlcontext", "0"))
|
||||||
self.forceQtNamespace = "forcens" in self.options
|
self.useDynamicType = int(args.get("dyntype", "0"))
|
||||||
self.passExceptions = "pe" in self.options
|
self.useFancy = int(args.get("fancy", "0"))
|
||||||
self.nativeMixed = "nativemixed" in self.options
|
self.forceQtNamespace = int(args.get("forcens", "0"))
|
||||||
self.autoDerefPointers = "autoderef" in self.options
|
self.passExceptions = int(args.get("passExceptions", "0"))
|
||||||
self.partialUpdate = "partial" in self.options
|
self.nativeMixed = int(args.get("nativemixed", "0"))
|
||||||
|
self.autoDerefPointers = int(args.get("autoderef", "0"))
|
||||||
|
self.partialUpdate = int(args.get("partial", "0"))
|
||||||
self.fallbackQtVersion = 0x50200
|
self.fallbackQtVersion = 0x50200
|
||||||
#warn("NAMESPACE: '%s'" % self.qtNamespace())
|
#warn("NAMESPACE: '%s'" % self.qtNamespace())
|
||||||
#warn("VARIABLES: %s" % self.varList)
|
#warn("VARIABLES: %s" % self.varList)
|
||||||
@@ -319,9 +283,9 @@ class Dumper(DumperBase):
|
|||||||
|
|
||||||
def handleWatches(self):
|
def handleWatches(self):
|
||||||
with OutputSafer(self):
|
with OutputSafer(self):
|
||||||
if len(self.watchers) > 0:
|
for watcher in self.watchers:
|
||||||
for watcher in self.watchers.split("##"):
|
iname = watcher['iname']
|
||||||
(exp, iname) = watcher.split("#")
|
exp = self.hexdecode(watcher['exp'])
|
||||||
self.handleWatch(exp, exp, iname)
|
self.handleWatch(exp, exp, iname)
|
||||||
|
|
||||||
def listOfLocals(self):
|
def listOfLocals(self):
|
||||||
@@ -405,7 +369,7 @@ class Dumper(DumperBase):
|
|||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
def run(self, args):
|
def showData(self, args):
|
||||||
self.prepare(args)
|
self.prepare(args)
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -481,14 +445,13 @@ class Dumper(DumperBase):
|
|||||||
self.output.append(']')
|
self.output.append(']')
|
||||||
self.typesToReport = {}
|
self.typesToReport = {}
|
||||||
|
|
||||||
if "forcens" in self.options:
|
if self.forceQtNamespace:
|
||||||
self.qtNamepaceToReport = self.qtNamespace()
|
self.qtNamepaceToReport = self.qtNamespace()
|
||||||
|
|
||||||
if self.qtNamespaceToReport:
|
if self.qtNamespaceToReport:
|
||||||
self.output.append(',qtnamespace="%s"' % self.qtNamespaceToReport)
|
self.output.append(',qtnamespace="%s"' % self.qtNamespaceToReport)
|
||||||
self.qtNamespaceToReport = None
|
self.qtNamespaceToReport = None
|
||||||
|
print(''.join(self.output))
|
||||||
return "".join(self.output)
|
|
||||||
|
|
||||||
def enterSubItem(self, item):
|
def enterSubItem(self, item):
|
||||||
if not item.iname:
|
if not item.iname:
|
||||||
@@ -1619,8 +1582,11 @@ class Dumper(DumperBase):
|
|||||||
if limit <= 0:
|
if limit <= 0:
|
||||||
limit = 10000
|
limit = 10000
|
||||||
options = args['options']
|
options = args['options']
|
||||||
|
opts = {}
|
||||||
|
if options == "nativemixed":
|
||||||
|
opts["nativemixed"] = 1
|
||||||
|
|
||||||
self.prepare("options:" + options + ",pe")
|
self.prepare(opts)
|
||||||
self.output = []
|
self.output = []
|
||||||
|
|
||||||
frame = gdb.newest_frame()
|
frame = gdb.newest_frame()
|
||||||
@@ -1699,6 +1665,21 @@ class Dumper(DumperBase):
|
|||||||
matplotQuit()
|
matplotQuit()
|
||||||
gdb.execute("quit")
|
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):
|
class CliDumper(Dumper):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -1788,7 +1769,7 @@ class CliDumper(Dumper):
|
|||||||
def putAddressRange(self, base, step):
|
def putAddressRange(self, base, step):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def run(self, args):
|
def showData(self, args):
|
||||||
arglist = args.split(' ')
|
arglist = args.split(' ')
|
||||||
name = ''
|
name = ''
|
||||||
if len(arglist) >= 1:
|
if len(arglist) >= 1:
|
||||||
@@ -1797,7 +1778,12 @@ class CliDumper(Dumper):
|
|||||||
if len(arglist) >= 2:
|
if len(arglist) >= 2:
|
||||||
for sub in arglist[1].split(','):
|
for sub in arglist[1].split(','):
|
||||||
allexpanded.append(name + '.' + sub)
|
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 + ' = '
|
self.output = name + ' = '
|
||||||
frame = gdb.selected_frame()
|
frame = gdb.selected_frame()
|
||||||
value = frame.read_var(name)
|
value = frame.read_var(name)
|
||||||
@@ -1805,12 +1791,6 @@ class CliDumper(Dumper):
|
|||||||
self.putItem(value)
|
self.putItem(value)
|
||||||
return self.output
|
return self.output
|
||||||
|
|
||||||
def pp(args):
|
|
||||||
return theDumper.run(args)
|
|
||||||
|
|
||||||
registerCommand("pp", pp)
|
|
||||||
|
|
||||||
|
|
||||||
# Global instance.
|
# Global instance.
|
||||||
if gdb.parameter('height') is None:
|
if gdb.parameter('height') is None:
|
||||||
theDumper = Dumper()
|
theDumper = Dumper()
|
||||||
@@ -1818,40 +1798,7 @@ else:
|
|||||||
import codecs
|
import codecs
|
||||||
theDumper = CliDumper()
|
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
|
# ThreadNames Command
|
||||||
#
|
#
|
||||||
|
@@ -4723,7 +4723,7 @@ QByteArray GdbEngine::dotEscape(QByteArray str)
|
|||||||
|
|
||||||
void GdbEngine::debugLastCommand()
|
void GdbEngine::debugLastCommand()
|
||||||
{
|
{
|
||||||
postCommand(m_lastDebuggableCommand, Discardable);
|
runCommand(m_lastDebuggableCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -4761,73 +4761,59 @@ void GdbEngine::updateLocalsPython(const UpdateParameters ¶ms)
|
|||||||
m_processedNames.clear();
|
m_processedNames.clear();
|
||||||
|
|
||||||
WatchHandler *handler = watchHandler();
|
WatchHandler *handler = watchHandler();
|
||||||
QByteArray expanded = "expanded:" + handler->expansionRequests() + ' ';
|
|
||||||
expanded += "typeformats:" + handler->typeFormatRequests() + ' ';
|
|
||||||
expanded += "formats:" + handler->individualFormatRequests();
|
|
||||||
|
|
||||||
QByteArray cutOff = " stringcutoff:"
|
DebuggerCommand cmd("showData");
|
||||||
+ action(MaximalStringLength)->value().toByteArray()
|
cmd.arg("expanded", handler->expansionRequests());
|
||||||
+ " displaystringlimit:"
|
cmd.arg("typeformats", handler->typeFormatRequests());
|
||||||
+ action(DisplayStringLimit)->value().toByteArray();
|
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
|
// Re-create tooltip items that are not filters on existing local variables in
|
||||||
// the tooltip model.
|
// the tooltip model.
|
||||||
QByteArray watchers;
|
cmd.beginList("watchers");
|
||||||
DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
|
DebuggerToolTipContexts toolTips = DebuggerToolTipManager::pendingTooltips(this);
|
||||||
foreach (const DebuggerToolTipContext &p, toolTips) {
|
foreach (const DebuggerToolTipContext &p, toolTips) {
|
||||||
if (!watchers.isEmpty())
|
cmd.beginGroup();
|
||||||
watchers += "##";
|
cmd.arg("iname", p.iname);
|
||||||
watchers += p.expression.toLatin1();
|
cmd.arg("exp", p.expression.toLatin1().toHex());
|
||||||
watchers += '#';
|
cmd.endGroup();
|
||||||
watchers += p.iname;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QByteArray, int> watcherNames = handler->watcherNames();
|
QHashIterator<QByteArray, int> it(WatchHandler::watcherNames());
|
||||||
QHashIterator<QByteArray, int> it(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();
|
||||||
}
|
}
|
||||||
|
cmd.endList();
|
||||||
|
|
||||||
const static bool alwaysVerbose = !qgetenv("QTC_DEBUGGER_PYTHON_VERBOSE").isEmpty();
|
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()) {
|
if (isNativeMixedActive()) {
|
||||||
StackFrame frame = stackHandler()->currentFrame();
|
StackFrame frame = stackHandler()->currentFrame();
|
||||||
if (frame.language == QmlLanguage)
|
if (frame.language == QmlLanguage)
|
||||||
context += " qmlcontext:0x" + QByteArray::number(frame.address, 16);
|
cmd.arg("qmlcontext", "0x" + QByteArray::number(frame.address, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray resultVar;
|
cmd.arg("resultvarname", m_resultVarName);
|
||||||
if (!m_resultVarName.isEmpty())
|
cmd.arg("vars", params.varList);
|
||||||
resultVar = "resultvarname:" + m_resultVarName + ' ';
|
cmd.flags = Discardable;
|
||||||
|
cmd.callback = [this, params](const DebuggerResponse &r) { handleStackFramePython(r, params.tryPartial); };
|
||||||
|
runCommand(cmd);
|
||||||
|
|
||||||
m_lastDebuggableCommand =
|
cmd.arg("passExceptions", true);
|
||||||
"bb options:pe," + options + " vars:" + params.varList + ' '
|
m_lastDebuggableCommand = cmd;
|
||||||
+ 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); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GdbEngine::handleStackFramePython(const DebuggerResponse &response, bool partial)
|
void GdbEngine::handleStackFramePython(const DebuggerResponse &response, bool partial)
|
||||||
|
@@ -486,7 +486,7 @@ protected:
|
|||||||
static QByteArray dotEscape(QByteArray str);
|
static QByteArray dotEscape(QByteArray str);
|
||||||
|
|
||||||
void debugLastCommand();
|
void debugLastCommand();
|
||||||
QByteArray m_lastDebuggableCommand;
|
DebuggerCommand m_lastDebuggableCommand;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void write(const QByteArray &data);
|
virtual void write(const QByteArray &data);
|
||||||
|
@@ -1204,10 +1204,14 @@ void tst_Dumpers::dumper()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QByteArray expanded;
|
QByteArray expanded;
|
||||||
|
QByteArray expandedq;
|
||||||
foreach (const QByteArray &iname, expandedINames) {
|
foreach (const QByteArray &iname, expandedINames) {
|
||||||
if (!expanded.isEmpty())
|
if (!expanded.isEmpty()) {
|
||||||
expanded.append(',');
|
expanded.append(',');
|
||||||
|
expandedq.append(',');
|
||||||
|
}
|
||||||
expanded += iname;
|
expanded += iname;
|
||||||
|
expandedq += '\'' + iname + '\'';
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray exe = m_debuggerBinary;
|
QByteArray exe = m_debuggerBinary;
|
||||||
@@ -1238,7 +1242,8 @@ void tst_Dumpers::dumper()
|
|||||||
"python from gdbbridge import *\n"
|
"python from gdbbridge import *\n"
|
||||||
"python theDumper.setupDumper()\n"
|
"python theDumper.setupDumper()\n"
|
||||||
"run " + nograb + "\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";
|
cmds += "quit\n";
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user