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/libcpp_stdtypes.py
|
||||||
debugger/stdtypes.py
|
debugger/stdtypes.py
|
||||||
debugger/utils.py
|
debugger/utils.py
|
||||||
|
debugger/loadorder.txt
|
||||||
)
|
)
|
||||||
|
|
||||||
# copy resource directories during build
|
# copy resource directories during build
|
||||||
|
|||||||
@@ -195,10 +195,16 @@ class DumperBase():
|
|||||||
self.childrenPrefix = 'children=['
|
self.childrenPrefix = 'children=['
|
||||||
self.childrenSuffix = '],'
|
self.childrenSuffix = '],'
|
||||||
|
|
||||||
self.dumpermodules = [
|
self.dumpermodules = []
|
||||||
os.path.splitext(os.path.basename(p))[0] for p in
|
|
||||||
glob.glob(os.path.join(os.path.dirname(__file__), '*types.py'))
|
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
|
# These values are never used, but the variables need to have
|
||||||
# some value base for the swapping logic in Children.__enter__()
|
# 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString dumperPath = runParameters().dumperPath.toUserOutput();
|
QString dumperPath = Core::ICore::resourcePath("debugger").toUserOutput();
|
||||||
dumperPath.replace('\\', "\\\\");
|
dumperPath.replace('\\', "\\\\");
|
||||||
runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand});
|
runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand});
|
||||||
runCommand({"from cdbbridge import Dumper", ScriptCommand});
|
runCommand({"from cdbbridge import Dumper", ScriptCommand});
|
||||||
|
|||||||
@@ -1036,11 +1036,6 @@ void DebuggerEngine::setRunTool(DebuggerRunTool *runTool)
|
|||||||
{
|
{
|
||||||
d->m_device = runTool->device();
|
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();
|
d->m_terminalRunner = runTool->terminalRunner();
|
||||||
|
|
||||||
validateRunParameters(d->m_runParameters);
|
validateRunParameters(d->m_runParameters);
|
||||||
|
|||||||
@@ -184,7 +184,6 @@ public:
|
|||||||
|
|
||||||
QStringList validationErrors;
|
QStringList validationErrors;
|
||||||
|
|
||||||
Utils::FilePath dumperPath;
|
|
||||||
int fallbackQtVersion = 0x50200;
|
int fallbackQtVersion = 0x50200;
|
||||||
|
|
||||||
// Common debugger constants.
|
// 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)) {
|
if (QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(kit)) {
|
||||||
const QVersionNumber qtVersion = baseQtVersion->qtVersion();
|
const QVersionNumber qtVersion = baseQtVersion->qtVersion();
|
||||||
m_runParameters.fallbackQtVersion = 0x10000 * qtVersion.majorVersion()
|
m_runParameters.fallbackQtVersion = 0x10000 * qtVersion.majorVersion()
|
||||||
|
|||||||
@@ -765,7 +765,8 @@ void GdbEngine::runCommand(const DebuggerCommand &command)
|
|||||||
if (cmd.flags & ConsoleCommand)
|
if (cmd.flags & ConsoleCommand)
|
||||||
cmd.function = "-interpreter-exec console \"" + cmd.function + '"';
|
cmd.function = "-interpreter-exec console \"" + cmd.function + '"';
|
||||||
cmd.function = QString::number(token) + cmd.function;
|
cmd.function = QString::number(token) + cmd.function;
|
||||||
showMessage(cmd.function, LogInput);
|
|
||||||
|
showMessage(cmd.function.left(100), LogInput);
|
||||||
|
|
||||||
if (m_scheduledTestResponses.contains(token)) {
|
if (m_scheduledTestResponses.contains(token)) {
|
||||||
// Fake response for test cases.
|
// Fake response for test cases.
|
||||||
@@ -3969,15 +3970,59 @@ void GdbEngine::handleGdbStarted()
|
|||||||
//if (terminal()->isUsable())
|
//if (terminal()->isUsable())
|
||||||
// runCommand({"set inferior-tty " + QString::fromUtf8(terminal()->slaveDevice())});
|
// 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'
|
runCommand({"python import sys, types"});
|
||||||
const FilePath uninstalledData = rp.debugger.command.executable().parentDir()
|
QStringList moduleList;
|
||||||
/ "data-directory/python";
|
for (const QByteArray &rawModuleName : toLoad->split('\n')) {
|
||||||
if (uninstalledData.exists())
|
const QString module = QString::fromUtf8(rawModuleName).trimmed();
|
||||||
runCommand({"python sys.path.append('" + uninstalledData.path() + "')"});
|
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();
|
const QString path = debuggerSettings()->extraDumperFile.value();
|
||||||
if (!path.isEmpty() && QFileInfo(path).isReadable()) {
|
if (!path.isEmpty() && QFileInfo(path).isReadable()) {
|
||||||
|
|||||||
@@ -219,7 +219,8 @@ void LldbEngine::handleLldbStarted()
|
|||||||
|
|
||||||
const DebuggerRunParameters &rp = runParameters();
|
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":
|
// This triggers reportState("enginesetupok") or "enginesetupfailed":
|
||||||
executeCommand("script from lldbbridge import *");
|
executeCommand("script from lldbbridge import *");
|
||||||
|
|
||||||
|
|||||||
@@ -677,9 +677,6 @@ bool DockerDevicePrivate::createContainer()
|
|||||||
if (m_data.useLocalUidGid)
|
if (m_data.useLocalUidGid)
|
||||||
dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())});
|
dockerCreate.addArgs({"-u", QString("%1:%2").arg(getuid()).arg(getgid())});
|
||||||
#endif
|
#endif
|
||||||
FilePath dumperPath = FilePath::fromString("/tmp/qtcreator/debugger");
|
|
||||||
addTemporaryMount(Core::ICore::resourcePath("debugger/"), dumperPath);
|
|
||||||
q->setDebugDumperPath(dumperPath);
|
|
||||||
|
|
||||||
dockerCreate.addArgs(createMountArgs());
|
dockerCreate.addArgs(createMountArgs());
|
||||||
|
|
||||||
|
|||||||
@@ -580,16 +580,6 @@ void IDevice::setDebugServerPath(const FilePath &path)
|
|||||||
d->debugServerPath = path;
|
d->debugServerPath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath IDevice::debugDumperPath() const
|
|
||||||
{
|
|
||||||
return d->debugDumperPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDevice::setDebugDumperPath(const FilePath &path)
|
|
||||||
{
|
|
||||||
d->debugDumperPath = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath IDevice::qmlRunCommand() const
|
FilePath IDevice::qmlRunCommand() const
|
||||||
{
|
{
|
||||||
return d->qmlRunCommand;
|
return d->qmlRunCommand;
|
||||||
|
|||||||
@@ -179,9 +179,6 @@ public:
|
|||||||
Utils::FilePath debugServerPath() const;
|
Utils::FilePath debugServerPath() const;
|
||||||
void setDebugServerPath(const Utils::FilePath &path);
|
void setDebugServerPath(const Utils::FilePath &path);
|
||||||
|
|
||||||
Utils::FilePath debugDumperPath() const;
|
|
||||||
void setDebugDumperPath(const Utils::FilePath &path);
|
|
||||||
|
|
||||||
Utils::FilePath qmlRunCommand() const;
|
Utils::FilePath qmlRunCommand() const;
|
||||||
void setQmlRunCommand(const Utils::FilePath &path);
|
void setQmlRunCommand(const Utils::FilePath &path);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user