Debugger: support piping the python dumper to cdb

Fixes: QTCREATORBUG-29000
Change-Id: I7454ded07829d06a33dc1b2ec95a838ca977ca95
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
David Schulz
2023-04-14 09:36:26 +02:00
parent d8be2491a5
commit 28d1d3ffe1
4 changed files with 69 additions and 16 deletions

View File

@@ -1,7 +1,7 @@
utils
gdbtracepoint
dumper
gdbbridge
***bridge***
boosttypes
creatortypes
libcpp_stdtypes

View File

@@ -954,9 +954,11 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd)
return;
}
if (dbgCmd.flags == ScriptCommand) {
if (dbgCmd.flags & ScriptCommand) {
// repack script command into an extension command
DebuggerCommand newCmd("script", ExtensionCommand, dbgCmd.callback);
if (dbgCmd.flags & DebuggerCommand::Silent)
newCmd.flags |= DebuggerCommand::Silent;
if (!dbgCmd.args.isNull())
newCmd.args = QString{dbgCmd.function + '(' + dbgCmd.argsToPython() + ')'};
else
@@ -975,7 +977,7 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd)
} else {
const int token = ++m_nextCommandToken;
StringInputStream str(fullCmd);
if (dbgCmd.flags == BuiltinCommand) {
if (dbgCmd.flags & BuiltinCommand) {
// Post a built-in-command producing free-format output with a callback.
// In order to catch the output, it is enclosed in 'echo' commands
// printing a specially formatted token to be identifiable in the output.
@@ -986,7 +988,7 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd)
showMessage("Command is longer than 4096 characters execution will likely fail.",
LogWarning);
}
} else if (dbgCmd.flags == ExtensionCommand) {
} else if (dbgCmd.flags & ExtensionCommand) {
// Post an extension command producing one-line output with a callback,
// pass along token for identification in hash.
@@ -1020,7 +1022,8 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd)
if (debug) {
qDebug("CdbEngine::postCommand: resulting command '%s'\n", qPrintable(fullCmd));
}
showMessage(cmd, LogInput);
if (!(dbgCmd.flags & DebuggerCommand::Silent))
showMessage(cmd, LogInput);
m_process.write(fullCmd);
}
@@ -2766,12 +2769,60 @@ void CdbEngine::setupScripting(const DebuggerResponse &response)
return;
}
QString dumperPath = Core::ICore::resourcePath("debugger").toUserOutput();
dumperPath.replace('\\', "\\\\");
runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand});
runCommand({"from cdbbridge import Dumper", ScriptCommand});
runCommand({"print(dir())", ScriptCommand});
runCommand({"theDumper = Dumper()", ScriptCommand});
if (runParameters().startMode == AttachToRemoteServer) {
FilePath dumperPath = Core::ICore::resourcePath("debugger");
const FilePath loadOrderFile = dumperPath / "loadorder.txt";
const expected_str<QByteArray> toLoad = loadOrderFile.fileContents();
if (!toLoad) {
Core::AsynchronousMessageBox::critical(
Tr::tr("Cannot Find Debugger Initialization Script"),
Tr::tr("Cannot read %1: %2").arg(loadOrderFile.toUserOutput(), toLoad.error()));
notifyEngineSetupFailed();
return;
}
runCommand({"import sys, types", ScriptCommand});
QStringList moduleList;
for (const QByteArray &rawModuleName : toLoad->split('\n')) {
QString module = QString::fromUtf8(rawModuleName).trimmed();
if (module.startsWith('#') || module.isEmpty())
continue;
if (module == "***bridge***")
module = "cdbbridge";
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("module = types.ModuleType('%1')").arg(module), ScriptCommand});
runCommand({QString("code = bytes.fromhex('%1').decode('utf-8')")
.arg(QString::fromUtf8(code->toHex())), ScriptCommand | DebuggerCommand::Silent});
runCommand({QString("exec(code, module.__dict__)"), ScriptCommand});
runCommand({QString("sys.modules['%1'] = module").arg(module), ScriptCommand});
runCommand({QString("import %1").arg(module), ScriptCommand});
if (module.endsWith("types"))
moduleList.append('"' + module + '"');
}
runCommand({"from cdbbridge import Dumper", ScriptCommand});
runCommand({"print(dir())", ScriptCommand});
runCommand({"theDumper = Dumper()", ScriptCommand});
runCommand({QString("theDumper.dumpermodules = [%1]").arg(moduleList.join(',')), ScriptCommand});
} else {
QString dumperPath = Core::ICore::resourcePath("debugger").toUserOutput();
dumperPath.replace('\\', "\\\\");
runCommand({"sys.path.insert(1, '" + dumperPath + "')", ScriptCommand});
runCommand({"from cdbbridge import Dumper", ScriptCommand});
runCommand({"print(dir())", ScriptCommand});
runCommand({"theDumper = Dumper()", ScriptCommand});
}
const QString path = debuggerSettings()->extraDumperFile.value();
if (!path.isEmpty() && QFileInfo(path).isReadable()) {

View File

@@ -110,9 +110,9 @@ private:
};
enum CommandFlags {
NoFlags = 0,
BuiltinCommand,
ExtensionCommand,
ScriptCommand
BuiltinCommand = DebuggerCommand::Silent << 1,
ExtensionCommand = DebuggerCommand::Silent << 2,
ScriptCommand = DebuggerCommand::Silent << 3
};
void init();

View File

@@ -3986,9 +3986,11 @@ void GdbEngine::handleGdbStarted()
runCommand({"python import sys, types"});
QStringList moduleList;
for (const QByteArray &rawModuleName : toLoad->split('\n')) {
const QString module = QString::fromUtf8(rawModuleName).trimmed();
if (module.startsWith('#'))
QString module = QString::fromUtf8(rawModuleName).trimmed();
if (module.startsWith('#') || module.isEmpty())
continue;
if (module == "***bridge***")
module = "gdbbridge";
const FilePath codeFile = dumperPath / (module + ".py");
const expected_str<QByteArray> code = codeFile.fileContents();