DAP: Add showing locals and stack trace

Change-Id: I5298b4c2daf45ec4503d4a210e02b7025253c054
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Artem Sokolovskii
2023-06-16 15:28:50 +02:00
parent 153cd8464d
commit 03aeee71f4
2 changed files with 99 additions and 103 deletions

View File

@@ -114,7 +114,7 @@ void DapEngine::setupEngine()
{ {
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state()); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
connect(&m_proc, &Process::started, this, &DapEngine::handleDabStarted); connect(&m_proc, &Process::started, this, &DapEngine::handleDapStarted);
connect(&m_proc, &Process::done, this, &DapEngine::handleDapDone); connect(&m_proc, &Process::done, this, &DapEngine::handleDapDone);
connect(&m_proc, &Process::readyReadStandardOutput, this, &DapEngine::readDapStandardOutput); connect(&m_proc, &Process::readyReadStandardOutput, this, &DapEngine::readDapStandardOutput);
connect(&m_proc, &Process::readyReadStandardError, this, &DapEngine::readDapStandardError); connect(&m_proc, &Process::readyReadStandardError, this, &DapEngine::readDapStandardError);
@@ -126,7 +126,7 @@ void DapEngine::setupEngine()
m_proc.setEnvironment(rp.debugger.environment); m_proc.setEnvironment(rp.debugger.environment);
m_proc.setCommand(cmd); m_proc.setCommand(cmd);
m_proc.start(); m_proc.start();
notifyEngineRunAndInferiorRunOk(); notifyEngineSetupOk();
} }
// From the docs: // From the docs:
@@ -140,9 +140,8 @@ void DapEngine::setupEngine()
// * client sends other future configuration requests // * client sends other future configuration requests
// * client sends one configurationDone request to indicate the end of the configuration. // * client sends one configurationDone request to indicate the end of the configuration.
void DapEngine::handleDabStarted() void DapEngine::handleDapStarted()
{ {
notifyEngineSetupOk();
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
// CHECK_STATE(EngineRunRequested); // CHECK_STATE(EngineRunRequested);
@@ -156,10 +155,10 @@ void DapEngine::handleDabStarted()
}} }}
}); });
qDebug() << "handleDabStarted"; qDebug() << "handleDapStarted";
} }
void DapEngine::handleDabConfigurationDone() void DapEngine::handleDapConfigurationDone()
{ {
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
@@ -167,11 +166,11 @@ void DapEngine::handleDabConfigurationDone()
postDirectCommand({{"command", "configurationDone"}, {"type", "request"}}); postDirectCommand({{"command", "configurationDone"}, {"type", "request"}});
qDebug() << "handleDabConfigurationDone"; qDebug() << "handleDapConfigurationDone";
} }
void DapEngine::handleDabLaunch() void DapEngine::handleDapLaunch()
{ {
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
@@ -184,7 +183,7 @@ void DapEngine::handleDabLaunch()
{"__restart", ""} {"__restart", ""}
}} }}
}); });
qDebug() << "handleDabLaunch"; qDebug() << "handleDapLaunch";
} }
void DapEngine::interruptInferior() void DapEngine::interruptInferior()
@@ -195,7 +194,7 @@ void DapEngine::interruptInferior()
}); });
} }
void DapEngine::dabStackTrace() void DapEngine::dapStackTrace()
{ {
if (m_currentThreadId == -1) if (m_currentThreadId == -1)
return; return;
@@ -206,16 +205,39 @@ void DapEngine::dabStackTrace()
{"arguments", QJsonObject{ {"arguments", QJsonObject{
{"threadId", m_currentThreadId}, {"threadId", m_currentThreadId},
{"startFrame", 0}, {"startFrame", 0},
{"levels", 1} {"levels", 10}
}}
});
}
void DapEngine::dapScopes()
{
postDirectCommand({
{"command", "scopes"},
{"type", "request"},
{"arguments", QJsonObject{
{"frameId", 0}
}} }}
}); });
} }
void DapEngine::threads() void DapEngine::threads()
{ {
postDirectCommand( postDirectCommand({
{{"command", "threads"}, {"command", "threads"},
{"type", "request"}}); {"type", "request"}
});
}
void DapEngine::dapVariables(int variablesReference)
{
postDirectCommand({
{"command", "variables"},
{"type", "request"},
{"arguments", QJsonObject{
{"variablesReference", variablesReference}
}}
});
} }
void DapEngine::executeStepIn(bool) void DapEngine::executeStepIn(bool)
@@ -628,7 +650,7 @@ void DapEngine::handleOutput(const QJsonDocument &data)
if (command == "configurationDone") { if (command == "configurationDone") {
showMessage("configurationDone", LogDebug); showMessage("configurationDone", LogDebug);
qDebug() << "configurationDone success"; qDebug() << "configurationDone success";
notifyInferiorRunOk(); notifyEngineRunAndInferiorRunOk();
return; return;
} }
@@ -650,9 +672,32 @@ void DapEngine::handleOutput(const QJsonDocument &data)
const int line = stackFrame.value("line").toInt(); const int line = stackFrame.value("line").toInt();
qDebug() << "stackTrace success" << file << line; qDebug() << "stackTrace success" << file << line;
gotoLocation(Location(file, line)); gotoLocation(Location(file, line));
refreshStack(stackFrames);
dapScopes();
return; return;
} }
if (command == "scopes") {
if (ob.value("success").toBool()) {
auto scopes = ob.value("body").toObject().value("scopes").toArray();
for (auto scope : scopes) {
const QString name = scope.toObject().value("name").toString();
const int variablesReference = scope.toObject().value("variablesReference").toInt();
qDebug() << "scoped success" << name << variablesReference;
if (name == "Locals")
dapVariables(variablesReference);
}
}
}
if (command == "variables") {
if (ob.value("success").toBool()) {
auto variables = ob.value("body").toObject().value("variables").toArray();
refreshLocals(variables);
}
}
if (command == "stepIn" || command == "stepOut" || command == "next") { if (command == "stepIn" || command == "stepOut" || command == "next") {
if (ob.value("success").toBool()) { if (ob.value("success").toBool()) {
showMessage(command, LogDebug); showMessage(command, LogDebug);
@@ -665,6 +710,7 @@ void DapEngine::handleOutput(const QJsonDocument &data)
if (command == "threads") { if (command == "threads") {
QJsonArray threads = ob.value("body").toObject().value("threads").toArray(); QJsonArray threads = ob.value("body").toObject().value("threads").toArray();
if (threads.isEmpty()) if (threads.isEmpty())
return; return;
@@ -712,13 +758,12 @@ void DapEngine::handleOutput(const QJsonDocument &data)
if (event == "initialized") { if (event == "initialized") {
showMessage(event, LogDebug); showMessage(event, LogDebug);
qDebug() << "initialize success"; qDebug() << "initialize success";
handleDabLaunch(); handleDapLaunch();
handleDabConfigurationDone(); handleDapConfigurationDone();
return; return;
} }
if (event == "stopped") { if (event == "stopped") {
ThreadsHandler *handler = threadsHandler();
m_currentThreadId = body.value("threadId").toInt(); m_currentThreadId = body.value("threadId").toInt();
showMessage(event, LogDebug); showMessage(event, LogDebug);
if (body.value("reason").toString() == "breakpoint") { if (body.value("reason").toString() == "breakpoint") {
@@ -729,15 +774,12 @@ void DapEngine::handleOutput(const QJsonDocument &data)
gotoLocation(Location(params.fileName, params.textPosition)); gotoLocation(Location(params.fileName, params.textPosition));
} }
if (body.value("reason").toString() == "pause"
|| body.value("reason").toString() == "step") {
dabStackTrace();
}
if (state() == InferiorStopRequested) if (state() == InferiorStopRequested)
notifyInferiorStopOk(); notifyInferiorStopOk();
else else
notifyInferiorSpontaneousStop(); notifyInferiorSpontaneousStop();
dapStackTrace();
threads(); threads();
return; return;
} }
@@ -760,7 +802,6 @@ void DapEngine::handleOutput(const QJsonDocument &data)
if (body.value("reason").toString() == "new") { if (body.value("reason").toString() == "new") {
if (breakpoint.value("verified").toBool()) { if (breakpoint.value("verified").toBool()) {
// bp->setPending(false);
notifyBreakpointInsertOk(bp); notifyBreakpointInsertOk(bp);
qDebug() << "breakpoint inserted"; qDebug() << "breakpoint inserted";
} else { } else {
@@ -790,38 +831,41 @@ void DapEngine::handleOutput(const QJsonDocument &data)
showMessage("UNKNOWN TYPE:" + type); showMessage("UNKNOWN TYPE:" + type);
} }
void DapEngine::refreshLocals(const GdbMi &vars) void DapEngine::refreshLocals(const QJsonArray &variables)
{ {
WatchHandler *handler = watchHandler(); watchHandler()->notifyUpdateStarted();
handler->resetValueCache(); for (auto variable : variables) {
handler->insertItems(vars); WatchItem *item = new WatchItem;
handler->notifyUpdateFinished(); const QString name = variable.toObject().value("name").toString();
item->iname = "local." + name;
updateToolTips(); item->name = name;
item->type = variable.toObject().value("type").toString();
item->value = variable.toObject().value("value").toString();
item->address = variable.toObject().value("address").toInt();
item->type = variable.toObject().value("type").toString();
qDebug() << "variable" << name << item->hexAddress();
watchHandler()->insertItem(item);
}
watchHandler()->notifyUpdateFinished();
} }
void DapEngine::refreshStack(const GdbMi &stack) void DapEngine::refreshStack(const QJsonArray &stackFrames)
{ {
StackHandler *handler = stackHandler(); StackHandler *handler = stackHandler();
StackFrames frames; StackFrames frames;
for (const GdbMi &item : stack["frames"]) { for (const auto &value : stackFrames) {
StackFrame frame; StackFrame frame;
frame.level = item["level"].data(); QJsonObject item = value.toObject();
frame.file = FilePath::fromString(item["file"].data()); frame.level = item.value("id").toString();
frame.function = item["function"].data(); frame.function = item.value("name").toString();
frame.module = item["function"].data(); frame.line = item.value("line").toInt();
frame.line = item["line"].toInt(); QJsonObject source = item.value("source").toObject();
frame.address = item["address"].toAddress(); frame.file = FilePath::fromString(source.value("path").toString());
GdbMi usable = item["usable"]; frame.address = item.value("instructionPointerReference").toInt();
if (usable.isValid())
frame.usable = usable.data().toInt();
else
frame.usable = frame.file.isReadableFile(); frame.usable = frame.file.isReadableFile();
frames.append(frame); frames.append(frame);
} }
bool canExpand = stack["hasmore"].toInt(); handler->setFrames(frames, false);
//action(ExpandStack)->setEnabled(canExpand);
handler->setFrames(frames, canExpand);
int index = stackHandler()->firstUsableIndex(); int index = stackHandler()->firstUsableIndex();
handler->setCurrentIndex(index); handler->setCurrentIndex(index);
@@ -837,22 +881,6 @@ void DapEngine::updateAll()
void DapEngine::updateLocals() void DapEngine::updateLocals()
{ {
// DebuggerCommand cmd("updateData");
// cmd.arg("nativeMixed", isNativeMixedActive());
// watchHandler()->appendFormatRequests(&cmd);
// watchHandler()->appendWatchersAndTooltipRequests(&cmd);
// const bool alwaysVerbose = qtcEnvironmentVariableIsSet("QTC_DEBUGGER_PYTHON_VERBOSE");
// cmd.arg("passexceptions", alwaysVerbose);
// cmd.arg("fancy", debuggerSettings()->useDebuggingHelpers.value());
// //cmd.arg("resultvarname", m_resultVarName);
// //m_lastDebuggableCommand = cmd;
// //m_lastDebuggableCommand.args.replace("\"passexceptions\":0", "\"passexceptions\":1");
// cmd.arg("frame", stackHandler()->currentIndex());
// watchHandler()->notifyUpdateStarted();
// runCommand(cmd);
} }
bool DapEngine::hasCapability(unsigned cap) const bool DapEngine::hasCapability(unsigned cap) const
@@ -866,40 +894,6 @@ void DapEngine::claimInitialBreakpoints()
{ {
BreakpointManager::claimBreakpointsForEngine(this); BreakpointManager::claimBreakpointsForEngine(this);
qDebug() << "claimInitialBreakpoints"; qDebug() << "claimInitialBreakpoints";
// const Breakpoints bps = breakHandler()->breakpoints();
// for (const Breakpoint &bp : bps)
// qDebug() << "breakpoit: " << bp->fileName() << bp->lineNumber();
// qDebug() << "claimInitialBreakpoints end";
// const DebuggerRunParameters &rp = runParameters();
// if (rp.startMode != AttachToCore) {
// showStatusMessage(Tr::tr("Setting breakpoints..."));
// showMessage(Tr::tr("Setting breakpoints..."));
// BreakpointManager::claimBreakpointsForEngine(this);
// const DebuggerSettings &s = *debuggerSettings();
// const bool onAbort = s.breakOnAbort.value();
// const bool onWarning = s.breakOnWarning.value();
// const bool onFatal = s.breakOnFatal.value();
// if (onAbort || onWarning || onFatal) {
// DebuggerCommand cmd("createSpecialBreakpoints");
// cmd.arg("breakonabort", onAbort);
// cmd.arg("breakonwarning", onWarning);
// cmd.arg("breakonfatal", onFatal);
// runCommand(cmd);
// }
// }
// // It is ok to cut corners here and not wait for createSpecialBreakpoints()'s
// // response, as the command is synchronous from Creator's point of view,
// // and even if it fails (e.g. due to stripped binaries), continuing with
// // the start up is the best we can do.
// if (!rp.commandsAfterConnect.isEmpty()) {
// const QString commands = expand(rp.commandsAfterConnect);
// for (const QString &command : commands.split('\n'))
// runCommand({command, NativeCommand});
// }
} }
DebuggerEngine *createDapEngine() DebuggerEngine *createDapEngine()

View File

@@ -67,8 +67,8 @@ private:
void postDirectCommand(const QJsonObject &ob); void postDirectCommand(const QJsonObject &ob);
void refreshLocation(const GdbMi &reportedLocation); void refreshLocation(const GdbMi &reportedLocation);
void refreshStack(const GdbMi &stack); void refreshStack(const QJsonArray &stackFrames);
void refreshLocals(const GdbMi &vars); void refreshLocals(const QJsonArray &variables);
void refreshModules(const GdbMi &modules); void refreshModules(const GdbMi &modules);
void refreshState(const GdbMi &reportedState); void refreshState(const GdbMi &reportedState);
void refreshSymbols(const GdbMi &symbols); void refreshSymbols(const GdbMi &symbols);
@@ -78,12 +78,14 @@ private:
void claimInitialBreakpoints(); void claimInitialBreakpoints();
void handleDabStarted(); void handleDapStarted();
void handleDabLaunch(); void handleDapLaunch();
void handleDabConfigurationDone(); void handleDapConfigurationDone();
void dabStackTrace(); void dapStackTrace();
void dapScopes();
void threads(); void threads();
void dapVariables(int variablesReference);
void handleDapDone(); void handleDapDone();
void readDapStandardOutput(); void readDapStandardOutput();