forked from qt-creator/qt-creator
DAP: Add showing locals and stack trace
Change-Id: I5298b4c2daf45ec4503d4a210e02b7025253c054 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -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 = frame.file.isReadableFile();
|
||||||
frame.usable = usable.data().toInt();
|
|
||||||
else
|
|
||||||
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()
|
||||||
|
@@ -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();
|
||||||
|
Reference in New Issue
Block a user