forked from qt-creator/qt-creator
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:
@@ -1107,13 +1107,53 @@ class Dumper(DumperBase):
|
|||||||
return
|
return
|
||||||
|
|
||||||
isNativeMixed = int(args.get('nativemixed', 0))
|
isNativeMixed = int(args.get('nativemixed', 0))
|
||||||
|
extraQml = int(args.get('extraqml', '0'))
|
||||||
|
|
||||||
limit = args.get('stacklimit', -1)
|
limit = args.get('stacklimit', -1)
|
||||||
(n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
|
(n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
|
||||||
self.currentCallContext = None
|
self.currentCallContext = None
|
||||||
result = 'stack={current-thread="%d"' % thread.GetThreadID()
|
result = 'stack={current-thread="%d"' % thread.GetThreadID()
|
||||||
result += ',frames=['
|
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)
|
frame = thread.GetFrameAtIndex(i)
|
||||||
if not frame.IsValid():
|
if not frame.IsValid():
|
||||||
isLimited = False
|
isLimited = False
|
||||||
|
@@ -715,27 +715,6 @@ void LldbEngine::updateAll()
|
|||||||
runCommand(cmd);
|
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
|
// Watch specific stuff
|
||||||
@@ -980,6 +959,33 @@ void LldbEngine::reloadDebuggingHelpers()
|
|||||||
updateAll();
|
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)
|
void LldbEngine::fetchDisassembler(DisassemblerAgent *agent)
|
||||||
{
|
{
|
||||||
QPointer<DisassemblerAgent> p(agent);
|
QPointer<DisassemblerAgent> p(agent);
|
||||||
@@ -1090,7 +1096,8 @@ bool LldbEngine::hasCapability(unsigned cap) const
|
|||||||
| OperateByInstructionCapability
|
| OperateByInstructionCapability
|
||||||
| RunToLineCapability
|
| RunToLineCapability
|
||||||
| WatchComplexExpressionsCapability
|
| WatchComplexExpressionsCapability
|
||||||
| MemoryAddressCapability))
|
| MemoryAddressCapability
|
||||||
|
| AdditionalQmlStackCapability))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (runParameters().startMode == AttachToCore)
|
if (runParameters().startMode == AttachToCore)
|
||||||
|
@@ -101,6 +101,7 @@ private:
|
|||||||
void reloadSourceFiles() override {}
|
void reloadSourceFiles() override {}
|
||||||
void reloadFullStack() override;
|
void reloadFullStack() override;
|
||||||
void reloadDebuggingHelpers() override;
|
void reloadDebuggingHelpers() override;
|
||||||
|
void loadAdditionalQmlStack() override;
|
||||||
void fetchDisassembler(Internal::DisassemblerAgent *) override;
|
void fetchDisassembler(Internal::DisassemblerAgent *) override;
|
||||||
|
|
||||||
void setRegisterValue(const QString &name, const QString &value) override;
|
void setRegisterValue(const QString &name, const QString &value) override;
|
||||||
@@ -125,7 +126,7 @@ private:
|
|||||||
void updateAll() override;
|
void updateAll() override;
|
||||||
void doUpdateLocals(const UpdateParameters ¶ms) override;
|
void doUpdateLocals(const UpdateParameters ¶ms) override;
|
||||||
void updateBreakpointData(const Breakpoint &bp, const GdbMi &bkpt, bool added);
|
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 runCommand(const DebuggerCommand &cmd) override;
|
||||||
void debugLastCommand() override;
|
void debugLastCommand() override;
|
||||||
|
Reference in New Issue
Block a user