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:
hjk
2023-04-03 18:46:43 +02:00
parent 808f5c0e1d
commit de546ff3ec
12 changed files with 80 additions and 37 deletions

View File

@@ -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

View File

@@ -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__()

View File

@@ -0,0 +1,13 @@
utils
gdbtracepoint
dumper
gdbbridge
boosttypes
creatortypes
libcpp_stdtypes
misctypes
opencvtypes
personaltypes
qttypes
stdtypes
android_stdtypes

View File

@@ -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});

View File

@@ -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);

View File

@@ -184,7 +184,6 @@ public:
QStringList validationErrors;
Utils::FilePath dumperPath;
int fallbackQtVersion = 0x50200;
// Common debugger constants.

View File

@@ -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()

View File

@@ -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()) {

View File

@@ -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 *");

View File

@@ -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());

View File

@@ -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;

View File

@@ -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);