forked from qt-creator/qt-creator
Debugger: Handle extra dumpers with LLDB
This generalizes part of the previously GDB-only code paths Change-Id: Id32798073e3c8bcb23bfedf463bebc866c8275e2 Reviewed-by: hjk <hjk@theqtcompany.com>
This commit is contained in:
@@ -34,6 +34,8 @@ import sys
|
||||
import base64
|
||||
import re
|
||||
import time
|
||||
import importlib
|
||||
|
||||
try:
|
||||
import subprocess
|
||||
hasSubprocess = True
|
||||
@@ -1635,6 +1637,65 @@ class DumperBase:
|
||||
self.currentNumChild = 0
|
||||
self.putNumChild(0)
|
||||
|
||||
def registerDumper(self, funcname, function):
|
||||
try:
|
||||
#warn("FUNCTION: %s " % funcname)
|
||||
#funcname = function.func_name
|
||||
if funcname.startswith("qdump__"):
|
||||
typename = funcname[7:]
|
||||
self.qqDumpers[typename] = function
|
||||
self.qqFormats[typename] = self.qqFormats.get(typename, "")
|
||||
elif funcname.startswith("qform__"):
|
||||
typename = funcname[7:]
|
||||
formats = ""
|
||||
try:
|
||||
formats = function()
|
||||
except:
|
||||
pass
|
||||
self.qqFormats[typename] = formats
|
||||
elif funcname.startswith("qedit__"):
|
||||
typename = funcname[7:]
|
||||
try:
|
||||
self.qqEditable[typename] = function
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
|
||||
def findDumperFunctions(self):
|
||||
self.qqDumpers = {}
|
||||
self.qqFormats = {}
|
||||
self.qqEditable = {}
|
||||
self.typeCache = {}
|
||||
|
||||
for mod in dumpermodules:
|
||||
m = importlib.import_module(mod)
|
||||
dic = m.__dict__
|
||||
for name in dic.keys():
|
||||
item = dic[name]
|
||||
self.registerDumper(name, item)
|
||||
|
||||
return self.reportDumpers()
|
||||
|
||||
def reportDumpers(self):
|
||||
result = "dumpers=["
|
||||
for key, value in self.qqFormats.items():
|
||||
if key in self.qqEditable:
|
||||
result += '{type="%s",formats="%s",editable="true"},' % (key, value)
|
||||
else:
|
||||
result += '{type="%s",formats="%s"},' % (key, value)
|
||||
result += ']'
|
||||
return result
|
||||
|
||||
def reloadDumper(self):
|
||||
for mod in dumpermodules:
|
||||
m = sys.modules[mod]
|
||||
if sys.version_info[0] >= 3:
|
||||
importlib.reload(m)
|
||||
else:
|
||||
reload(m)
|
||||
|
||||
findDumperFunctions()
|
||||
|
||||
# Some "Enums"
|
||||
|
||||
@@ -1681,3 +1742,12 @@ DisplayUtf8String \
|
||||
= range(6)
|
||||
|
||||
|
||||
dumpermodules = [
|
||||
"qttypes",
|
||||
"stdtypes",
|
||||
"misctypes",
|
||||
"boosttypes",
|
||||
"creatortypes",
|
||||
"personaltypes",
|
||||
]
|
||||
|
||||
|
@@ -14,25 +14,11 @@ import sys
|
||||
import struct
|
||||
import types
|
||||
|
||||
import importlib
|
||||
|
||||
def warn(message):
|
||||
print("XXX: %s\n" % message.encode("latin1"))
|
||||
|
||||
from dumper import *
|
||||
|
||||
dumpermodules = [
|
||||
"qttypes",
|
||||
"stdtypes",
|
||||
"misctypes",
|
||||
"boosttypes",
|
||||
"creatortypes",
|
||||
"personaltypes",
|
||||
]
|
||||
|
||||
for mod in dumpermodules:
|
||||
importlib.import_module(mod)
|
||||
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
@@ -150,8 +136,7 @@ ScanStackCommand()
|
||||
|
||||
|
||||
def bbsetup(args = ''):
|
||||
theDumper.bbsetup()
|
||||
print(theDumper.reportDumpers())
|
||||
print(theDumper.findDumperFunctions())
|
||||
|
||||
registerCommand("bbsetup", bbsetup)
|
||||
|
||||
@@ -1423,55 +1408,6 @@ class Dumper(DumperBase):
|
||||
with Children(self, 1):
|
||||
self.listAnonymous(value, name, field.type)
|
||||
|
||||
def registerDumper(self, funcname, function):
|
||||
try:
|
||||
#warn("FUNCTION: %s " % funcname)
|
||||
#funcname = function.func_name
|
||||
if funcname.startswith("qdump__"):
|
||||
typename = funcname[7:]
|
||||
self.qqDumpers[typename] = function
|
||||
self.qqFormats[typename] = self.qqFormats.get(typename, "")
|
||||
elif funcname.startswith("qform__"):
|
||||
typename = funcname[7:]
|
||||
formats = ""
|
||||
try:
|
||||
formats = function()
|
||||
except:
|
||||
pass
|
||||
self.qqFormats[typename] = formats
|
||||
elif funcname.startswith("qedit__"):
|
||||
typename = funcname[7:]
|
||||
try:
|
||||
self.qqEditable[typename] = function
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
|
||||
def bbsetup(self):
|
||||
self.qqDumpers = {}
|
||||
self.qqFormats = {}
|
||||
self.qqEditable = {}
|
||||
self.typeCache = {}
|
||||
|
||||
for mod in dumpermodules:
|
||||
m = importlib.import_module(mod)
|
||||
dic = m.__dict__
|
||||
for name in dic.keys():
|
||||
item = dic[name]
|
||||
self.registerDumper(name, item)
|
||||
|
||||
|
||||
def reportDumpers(self):
|
||||
result = "dumpers=["
|
||||
for key, value in self.qqFormats.items():
|
||||
if key in self.qqEditable:
|
||||
result += '{type="%s",formats="%s",editable="true"},' % (key, value)
|
||||
else:
|
||||
result += '{type="%s",formats="%s"},' % (key, value)
|
||||
result += ']'
|
||||
return result
|
||||
|
||||
#def threadname(self, maximalStackDepth, objectPrivateType):
|
||||
# e = gdb.selected_frame()
|
||||
# out = ""
|
||||
@@ -2044,15 +1980,8 @@ registerCommand("threadnames", threadnames)
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
def reloadDumper(arg):
|
||||
for mod in dumpermodules:
|
||||
m = sys.modules[mod]
|
||||
if sys.version_info[0] >= 3:
|
||||
importlib.reload(m)
|
||||
else:
|
||||
reload(m)
|
||||
|
||||
bbsetup()
|
||||
def reloadDumper(_):
|
||||
theDumper.reloadDumper();
|
||||
|
||||
registerCommand("reload", reloadDumper)
|
||||
|
||||
|
@@ -672,7 +672,6 @@ class Dumper(DumperBase):
|
||||
self.target = self.debugger.CreateTarget(self.executable_, None, None, True, error)
|
||||
else:
|
||||
self.target = self.debugger.CreateTarget(None, None, None, True, error)
|
||||
self.importDumpers()
|
||||
|
||||
state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
|
||||
self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
|
||||
@@ -1583,7 +1582,7 @@ class Dumper(DumperBase):
|
||||
path = args['path']
|
||||
(head, tail) = os.path.split(path)
|
||||
sys.path.insert(1, head)
|
||||
#dumpermodules.append(os.path.splitext(tail)[0])
|
||||
dumpermodules.append(os.path.splitext(tail)[0])
|
||||
self.report('ok')
|
||||
|
||||
def updateData(self, args):
|
||||
@@ -1642,6 +1641,10 @@ class Dumper(DumperBase):
|
||||
result += ',offset="%s"},' % (addr - base)
|
||||
self.report(result + ']')
|
||||
|
||||
def loadDumperFiles(self, _ = None):
|
||||
result = self.findDumperFunctions()
|
||||
self.report(result)
|
||||
|
||||
def fetchMemory(self, args):
|
||||
address = args['address']
|
||||
length = args['length']
|
||||
@@ -1668,35 +1671,6 @@ class Dumper(DumperBase):
|
||||
self.reportError(error)
|
||||
self.reportVariables()
|
||||
|
||||
def registerDumper(self, function):
|
||||
if hasattr(function, 'func_name'):
|
||||
funcname = function.func_name
|
||||
if funcname.startswith("qdump__"):
|
||||
type = funcname[7:]
|
||||
self.qqDumpers[type] = function
|
||||
self.qqFormats[type] = self.qqFormats.get(type, "")
|
||||
elif funcname.startswith("qform__"):
|
||||
type = funcname[7:]
|
||||
formats = ""
|
||||
try:
|
||||
formats = function()
|
||||
except:
|
||||
pass
|
||||
self.qqFormats[type] = formats
|
||||
elif funcname.startswith("qedit__"):
|
||||
type = funcname[7:]
|
||||
try:
|
||||
self.qqEditable[type] = function
|
||||
except:
|
||||
pass
|
||||
|
||||
def importDumpers(self, _ = None):
|
||||
result = lldb.SBCommandReturnObject()
|
||||
interpreter = self.debugger.GetCommandInterpreter()
|
||||
items = globals()
|
||||
for key in items:
|
||||
self.registerDumper(items[key])
|
||||
|
||||
def execute(self, args):
|
||||
getattr(self, args['cmd'])(args)
|
||||
self.report('token="%s"' % args['token'])
|
||||
@@ -1754,7 +1728,7 @@ class Tester(Dumper):
|
||||
self.expandedINames = set(sys.argv[3].split(','))
|
||||
self.passExceptions = True
|
||||
|
||||
self.importDumpers()
|
||||
self.loadDumperFiles()
|
||||
error = lldb.SBError()
|
||||
self.target = self.debugger.CreateTarget(sys.argv[2],
|
||||
None, None, True, error)
|
||||
|
@@ -1737,22 +1737,7 @@ void GdbEngine::handlePythonSetup(const GdbResponse &response)
|
||||
if (response.resultClass == GdbResultDone) {
|
||||
GdbMi data;
|
||||
data.fromStringMultiple(response.consoleStreamOutput);
|
||||
const GdbMi dumpers = data["dumpers"];
|
||||
foreach (const GdbMi &dumper, dumpers.children()) {
|
||||
QByteArray type = dumper["type"].data();
|
||||
QStringList formats(tr("Raw structure"));
|
||||
foreach (const QByteArray &format,
|
||||
dumper["formats"].data().split(',')) {
|
||||
if (format == "Normal")
|
||||
formats.append(tr("Normal"));
|
||||
else if (format == "Displayed")
|
||||
formats.append(tr("Displayed"));
|
||||
else if (!format.isEmpty())
|
||||
formats.append(_(format));
|
||||
}
|
||||
watchHandler()->addTypeFormats(type, formats);
|
||||
}
|
||||
|
||||
watchHandler()->addDumpers(data["dumpers"]);
|
||||
loadInitScript();
|
||||
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
|
||||
showMessage(_("ENGINE SUCCESSFULLY STARTED"));
|
||||
|
@@ -281,10 +281,13 @@ void LldbEngine::setupInferior()
|
||||
const QString commands = stringSetting(ExtraDumperCommands);
|
||||
if (!commands.isEmpty()) {
|
||||
Command cmd("executeDebuggerCommand");
|
||||
cmd.arg(commands.toUtf8());
|
||||
cmd.arg("commands", commands.toUtf8());
|
||||
runCommand(cmd);
|
||||
}
|
||||
|
||||
Command cmd1("loadDumperFiles");
|
||||
runCommand(cmd1);
|
||||
|
||||
QString executable;
|
||||
QtcProcess::Arguments args;
|
||||
QtcProcess::prepareCommand(QFileInfo(sp.executable).absoluteFilePath(),
|
||||
@@ -409,6 +412,8 @@ void LldbEngine::handleResponse(const QByteArray &response)
|
||||
const QByteArray name = item.name();
|
||||
if (name == "data")
|
||||
refreshLocals(item);
|
||||
else if (name == "dumpers")
|
||||
watchHandler()->addDumpers(item);
|
||||
else if (name == "stack")
|
||||
refreshStack(item);
|
||||
else if (name == "stack-position")
|
||||
|
@@ -1783,6 +1783,22 @@ QByteArray WatchHandler::individualFormatRequests() const
|
||||
return ba;
|
||||
}
|
||||
|
||||
void WatchHandler::addDumpers(const GdbMi &dumpers)
|
||||
{
|
||||
foreach (const GdbMi &dumper, dumpers.children()) {
|
||||
QStringList formats(tr("Raw structure"));
|
||||
foreach (const QByteArray &format, dumper["formats"].data().split(',')) {
|
||||
if (format == "Normal")
|
||||
formats.append(tr("Normal"));
|
||||
else if (format == "Displayed")
|
||||
formats.append(tr("Displayed"));
|
||||
else if (!format.isEmpty())
|
||||
formats.append(QString::fromLatin1(format));
|
||||
}
|
||||
addTypeFormats(dumper["type"].data(), formats);
|
||||
}
|
||||
}
|
||||
|
||||
void WatchHandler::addTypeFormats(const QByteArray &type, const QStringList &formats)
|
||||
{
|
||||
m_model->m_reportedTypeFormats.insert(QLatin1String(stripForFormat(type)), formats);
|
||||
|
@@ -217,6 +217,7 @@ public:
|
||||
|
||||
int format(const QByteArray &iname) const;
|
||||
|
||||
void addDumpers(const GdbMi &dumpers);
|
||||
void addTypeFormats(const QByteArray &type, const QStringList &formats);
|
||||
void setTypeFormats(const DumperTypeFormats &typeFormats);
|
||||
DumperTypeFormats typeFormats() const;
|
||||
|
Reference in New Issue
Block a user