forked from qt-creator/qt-creator
Debugger: Support piping dumpers into gdb
This allows using dumpers available on the host being used from remotely running gdb. No lldb/cdb yet. Task-number: QTCREATORBUG-29000 Task-number: QTCREATORBUG-16246 Change-Id: Ib1a40a8c0284dcf41e8800d70ca3e632c699b2fa Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -35,6 +35,7 @@ set(resource_files
|
||||
debugger/libcpp_stdtypes.py
|
||||
debugger/stdtypes.py
|
||||
debugger/utils.py
|
||||
debugger/loadorder.txt
|
||||
)
|
||||
|
||||
# copy resource directories during build
|
||||
|
@@ -195,10 +195,16 @@ class DumperBase():
|
||||
self.childrenPrefix = 'children=['
|
||||
self.childrenSuffix = '],'
|
||||
|
||||
self.dumpermodules = [
|
||||
os.path.splitext(os.path.basename(p))[0] for p in
|
||||
glob.glob(os.path.join(os.path.dirname(__file__), '*types.py'))
|
||||
]
|
||||
self.dumpermodules = []
|
||||
|
||||
try:
|
||||
# Fails in the piping case
|
||||
self.dumpermodules = [
|
||||
os.path.splitext(os.path.basename(p))[0] for p in
|
||||
glob.glob(os.path.join(os.path.dirname(__file__), '*types.py'))
|
||||
]
|
||||
except:
|
||||
pass
|
||||
|
||||
# These values are never used, but the variables need to have
|
||||
# some value base for the swapping logic in Children.__enter__()
|
||||
|
13
share/qtcreator/debugger/loadorder.txt
Normal file
13
share/qtcreator/debugger/loadorder.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
utils
|
||||
gdbtracepoint
|
||||
dumper
|
||||
gdbbridge
|
||||
boosttypes
|
||||
creatortypes
|
||||
libcpp_stdtypes
|
||||
misctypes
|
||||
opencvtypes
|
||||
personaltypes
|
||||
qttypes
|
||||
stdtypes
|
||||
android_stdtypes
|
@@ -2766,7 +2766,7 @@ void CdbEngine::setupScripting(const DebuggerResponse &response)
|
||||
return;
|
||||
}
|
||||
|
||||
QString dumperPath = runParameters().dumperPath.toUserOutput();
|
||||
QString dumperPath = Core::ICore::resourcePath("debugger").toUserOutput();
|
||||
dumperPath.replace('\\', "\\\\");
|
||||
runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand});
|
||||
runCommand({"from cdbbridge import Dumper", ScriptCommand});
|
||||
|
@@ -1036,11 +1036,6 @@ void DebuggerEngine::setRunTool(DebuggerRunTool *runTool)
|
||||
{
|
||||
d->m_device = runTool->device();
|
||||
|
||||
IDevice::ConstPtr debuggerDevice =
|
||||
DeviceManager::deviceForPath(d->m_runParameters.debugger.command.executable());
|
||||
if (QTC_GUARD(debuggerDevice))
|
||||
d->m_runParameters.dumperPath = debuggerDevice->debugDumperPath();
|
||||
|
||||
d->m_terminalRunner = runTool->terminalRunner();
|
||||
|
||||
validateRunParameters(d->m_runParameters);
|
||||
|
@@ -184,7 +184,6 @@ public:
|
||||
|
||||
QStringList validationErrors;
|
||||
|
||||
Utils::FilePath dumperPath;
|
||||
int fallbackQtVersion = 0x50200;
|
||||
|
||||
// Common debugger constants.
|
||||
|
@@ -928,7 +928,6 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
|
||||
}
|
||||
}
|
||||
|
||||
m_runParameters.dumperPath = Core::ICore::resourcePath("debugger/");
|
||||
if (QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(kit)) {
|
||||
const QVersionNumber qtVersion = baseQtVersion->qtVersion();
|
||||
m_runParameters.fallbackQtVersion = 0x10000 * qtVersion.majorVersion()
|
||||
|
@@ -765,7 +765,8 @@ void GdbEngine::runCommand(const DebuggerCommand &command)
|
||||
if (cmd.flags & ConsoleCommand)
|
||||
cmd.function = "-interpreter-exec console \"" + cmd.function + '"';
|
||||
cmd.function = QString::number(token) + cmd.function;
|
||||
showMessage(cmd.function, LogInput);
|
||||
|
||||
showMessage(cmd.function.left(100), LogInput);
|
||||
|
||||
if (m_scheduledTestResponses.contains(token)) {
|
||||
// Fake response for test cases.
|
||||
@@ -3969,15 +3970,59 @@ void GdbEngine::handleGdbStarted()
|
||||
//if (terminal()->isUsable())
|
||||
// runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())});
|
||||
|
||||
runCommand({"python sys.path.insert(1, '" + rp.dumperPath.path() + "')"});
|
||||
const FilePath dumperPath = ICore::resourcePath("debugger");
|
||||
if (rp.debugger.command.executable().needsDevice()) {
|
||||
// Gdb itself running remotely.
|
||||
const FilePath loadOrderFile = dumperPath / "loadorder.txt";
|
||||
const expected_str<QByteArray> toLoad = loadOrderFile.fileContents();
|
||||
if (!toLoad) {
|
||||
AsynchronousMessageBox::critical(
|
||||
Tr::tr("Cannot Find Debugger Initialization Script"),
|
||||
Tr::tr("Cannot read %1: %2").arg(loadOrderFile.toUserOutput(), toLoad.error()));
|
||||
notifyEngineSetupFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
// This is useful (only) in custom gdb builds that did not run 'make install'
|
||||
const FilePath uninstalledData = rp.debugger.command.executable().parentDir()
|
||||
/ "data-directory/python";
|
||||
if (uninstalledData.exists())
|
||||
runCommand({"python sys.path.append('" + uninstalledData.path() + "')"});
|
||||
runCommand({"python import sys, types"});
|
||||
QStringList moduleList;
|
||||
for (const QByteArray &rawModuleName : toLoad->split('\n')) {
|
||||
const QString module = QString::fromUtf8(rawModuleName).trimmed();
|
||||
if (module.startsWith('#'))
|
||||
continue;
|
||||
|
||||
runCommand({"python from gdbbridge import *"});
|
||||
const FilePath codeFile = dumperPath / (module + ".py");
|
||||
const expected_str<QByteArray> code = codeFile.fileContents();
|
||||
if (!code) {
|
||||
qDebug() << Tr::tr("Cannot read %1: %2").arg(codeFile.toUserOutput(), code.error());
|
||||
continue;
|
||||
}
|
||||
|
||||
showMessage("Reading " + codeFile.toUserOutput(), LogInput);
|
||||
runCommand({QString("python module = types.ModuleType('%1')").arg(module)});
|
||||
runCommand({QString("python code = bytes.fromhex('%1').decode('utf-8')")
|
||||
.arg(QString::fromUtf8(code->toHex()))});
|
||||
runCommand({QString("python exec(code, module.__dict__)")});
|
||||
runCommand({QString("python sys.modules['%1'] = module").arg(module)});
|
||||
runCommand({QString("python import %1").arg(module)});
|
||||
|
||||
if (module.endsWith("types"))
|
||||
moduleList.append('"' + module + '"');
|
||||
}
|
||||
|
||||
runCommand({"python from gdbbridge import *"});
|
||||
runCommand(QString("python theDumper.dumpermodules = [%1]").arg(moduleList.join(',')));
|
||||
|
||||
} else {
|
||||
// Gdb on local host
|
||||
// This is useful (only) in custom gdb builds that did not run 'make install'
|
||||
const FilePath uninstalledData = rp.debugger.command.executable().parentDir()
|
||||
/ "data-directory/python";
|
||||
if (uninstalledData.exists())
|
||||
runCommand({"python sys.path.append('" + uninstalledData.path() + "')"});
|
||||
|
||||
runCommand({"python sys.path.insert(1, '" + dumperPath.path() + "')"});
|
||||
runCommand({"python from gdbbridge import *"});
|
||||
}
|
||||
|
||||
const QString path = debuggerSettings()->extraDumperFile.value();
|
||||
if (!path.isEmpty() && QFileInfo(path).isReadable()) {
|
||||
|
@@ -219,7 +219,8 @@ void LldbEngine::handleLldbStarted()
|
||||
|
||||
const DebuggerRunParameters &rp = runParameters();
|
||||
|
||||
executeCommand("script sys.path.insert(1, '" + rp.dumperPath.path() + "')");
|
||||
QString dumperPath = ICore::resourcePath("debugger").path();
|
||||
executeCommand("script sys.path.insert(1, '" + dumperPath + "')");
|
||||
// This triggers reportState("enginesetupok") or "enginesetupfailed":
|
||||
executeCommand("script from lldbbridge import *");
|
||||
|
||||
|
@@ -677,9 +677,6 @@ bool DockerDevicePrivate::createContainer()
|
||||
if (m_data.useLocalUidGid)
|
||||
dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())});
|
||||
#endif
|
||||
FilePath dumperPath = FilePath::fromString("/tmp/qtcreator/debugger");
|
||||
addTemporaryMount(Core::ICore::resourcePath("debugger/"), dumperPath);
|
||||
q->setDebugDumperPath(dumperPath);
|
||||
|
||||
dockerCreate.addArgs(createMountArgs());
|
||||
|
||||
|
@@ -580,16 +580,6 @@ void IDevice::setDebugServerPath(const FilePath &path)
|
||||
d->debugServerPath = path;
|
||||
}
|
||||
|
||||
FilePath IDevice::debugDumperPath() const
|
||||
{
|
||||
return d->debugDumperPath;
|
||||
}
|
||||
|
||||
void IDevice::setDebugDumperPath(const FilePath &path)
|
||||
{
|
||||
d->debugDumperPath = path;
|
||||
}
|
||||
|
||||
FilePath IDevice::qmlRunCommand() const
|
||||
{
|
||||
return d->qmlRunCommand;
|
||||
|
@@ -179,9 +179,6 @@ public:
|
||||
Utils::FilePath debugServerPath() const;
|
||||
void setDebugServerPath(const Utils::FilePath &path);
|
||||
|
||||
Utils::FilePath debugDumperPath() const;
|
||||
void setDebugDumperPath(const Utils::FilePath &path);
|
||||
|
||||
Utils::FilePath qmlRunCommand() const;
|
||||
void setQmlRunCommand(const Utils::FilePath &path);
|
||||
|
||||
|
Reference in New Issue
Block a user