Debugger: Implement "Load QML Stack" feature for LLDB

Fixes: QTCREATORBUG-25554
Change-Id: Ieafa22581c294d9b993efe077354750a8f986424
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2021-05-04 14:55:33 +02:00
parent 26a824184c
commit 75ededf4a9
3 changed files with 72 additions and 24 deletions

View File

@@ -1107,13 +1107,53 @@ class Dumper(DumperBase):
return
isNativeMixed = int(args.get('nativemixed', 0))
extraQml = int(args.get('extraqml', '0'))
limit = args.get('stacklimit', -1)
(n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
self.currentCallContext = None
result = 'stack={current-thread="%d"' % thread.GetThreadID()
result += ',frames=['
for i in range(n):
ii = 0
if extraQml:
ns = self.qtNamespace()
needle = self.qtNamespace() + 'QV4::ExecutionEngine'
pats = [
'{0}qt_v4StackTraceForEngine((void*)0x{1:x})',
'{0}qt_v4StackTrace((({0}QV4::ExecutionEngine *)0x{1:x})->currentContext())',
'{0}qt_v4StackTrace((({0}QV4::ExecutionEngine *)0x{1:x})->currentContext)',
]
done = False
while ii < n and not done:
res = None
frame = thread.GetFrameAtIndex(ii)
for variable in frame.GetVariables(True, True, False, True):
if not variable.GetType().IsPointerType():
continue
derefvar = variable.Dereference()
if derefvar.GetType().GetName() != needle:
continue
addr = derefvar.GetLoadAddress()
for pat in pats:
exp = pat.format(ns, addr)
val = frame.EvaluateExpression(exp)
err = val.GetError()
res = str(val)
if err.Fail():
continue
pos = res.find('"stack=[')
if pos == -1:
continue
res = res[pos + 8:-2]
res = res.replace('\\\"', '\"')
res = res.replace('func=', 'function=')
result += res
done = True
break
ii += 1
for i in range(n - ii):
frame = thread.GetFrameAtIndex(i)
if not frame.IsValid():
isLimited = False

View File

@@ -715,27 +715,6 @@ void LldbEngine::updateAll()
runCommand(cmd);
}
void LldbEngine::reloadFullStack()
{
fetchStack(-1);
}
void LldbEngine::fetchStack(int limit)
{
DebuggerCommand cmd("fetchStack");
cmd.arg("nativemixed", isNativeMixedActive());
cmd.arg("stacklimit", limit);
cmd.arg("context", stackHandler()->currentFrame().context);
cmd.callback = [this](const DebuggerResponse &response) {
const GdbMi &stack = response.data["stack"];
const bool isFull = !stack["hasmore"].toInt();
stackHandler()->setFramesAndCurrentIndex(stack["frames"], isFull);
activateFrame(stackHandler()->currentIndex());
};
runCommand(cmd);
}
//////////////////////////////////////////////////////////////////////
//
// Watch specific stuff
@@ -980,6 +959,33 @@ void LldbEngine::reloadDebuggingHelpers()
updateAll();
}
void LldbEngine::loadAdditionalQmlStack()
{
fetchStack(-1, true);
}
void LldbEngine::reloadFullStack()
{
fetchStack(-1, false);
}
void LldbEngine::fetchStack(int limit, bool extraQml)
{
DebuggerCommand cmd("fetchStack");
cmd.arg("nativemixed", isNativeMixedActive());
cmd.arg("stacklimit", limit);
cmd.arg("context", stackHandler()->currentFrame().context);
cmd.arg("extraqml", int(extraQml));
cmd.callback = [this](const DebuggerResponse &response) {
const GdbMi &stack = response.data["stack"];
const bool isFull = !stack["hasmore"].toInt();
stackHandler()->setFramesAndCurrentIndex(stack["frames"], isFull);
activateFrame(stackHandler()->currentIndex());
};
runCommand(cmd);
}
void LldbEngine::fetchDisassembler(DisassemblerAgent *agent)
{
QPointer<DisassemblerAgent> p(agent);
@@ -1090,7 +1096,8 @@ bool LldbEngine::hasCapability(unsigned cap) const
| OperateByInstructionCapability
| RunToLineCapability
| WatchComplexExpressionsCapability
| MemoryAddressCapability))
| MemoryAddressCapability
| AdditionalQmlStackCapability))
return true;
if (runParameters().startMode == AttachToCore)

View File

@@ -101,6 +101,7 @@ private:
void reloadSourceFiles() override {}
void reloadFullStack() override;
void reloadDebuggingHelpers() override;
void loadAdditionalQmlStack() override;
void fetchDisassembler(Internal::DisassemblerAgent *) override;
void setRegisterValue(const QString &name, const QString &value) override;
@@ -125,7 +126,7 @@ private:
void updateAll() override;
void doUpdateLocals(const UpdateParameters &params) override;
void updateBreakpointData(const Breakpoint &bp, const GdbMi &bkpt, bool added);
void fetchStack(int limit);
void fetchStack(int limit, bool alsoQml = false);
void runCommand(const DebuggerCommand &cmd) override;
void debugLastCommand() override;