forked from qt-creator/qt-creator
Debugger: Fix QML extra stack loading for GDB
Change-Id: I702bb8f183e93fe25857115225fa55607ffb1674 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -998,9 +998,10 @@ class Dumper(DumperBase):
|
||||
gdb.execute('continue')
|
||||
|
||||
def fetchStack(self, args):
|
||||
def fromNativePath(str):
|
||||
return str.replace('\\', '/')
|
||||
def fromNativePath(string):
|
||||
return string.replace('\\', '/')
|
||||
|
||||
extraQml = int(args.get('extraqml', '0'))
|
||||
limit = int(args['limit'])
|
||||
if limit <= 0:
|
||||
limit = 10000
|
||||
@@ -1008,8 +1009,42 @@ class Dumper(DumperBase):
|
||||
self.prepare(args)
|
||||
self.output = []
|
||||
|
||||
frame = gdb.newest_frame()
|
||||
i = 0
|
||||
if extraQml:
|
||||
frame = gdb.newest_frame()
|
||||
ns = self.qtNamespace()
|
||||
needle = self.qtNamespace() + 'QV4::ExecutionEngine'
|
||||
pat = "%sqt_v4StackTrace(((%sQV4::ExecutionEngine *)0x%x)->currentContext)"
|
||||
done = False
|
||||
while i < limit and frame and not done:
|
||||
block = None
|
||||
try:
|
||||
block = frame.block()
|
||||
except:
|
||||
pass
|
||||
if block is not None:
|
||||
for symbol in block:
|
||||
if symbol.is_variable or symbol.is_argument:
|
||||
value = symbol.value(frame)
|
||||
typeobj = value.type
|
||||
if typeobj.code == gdb.TYPE_CODE_PTR:
|
||||
dereftype = typeobj.target().unqualified()
|
||||
if dereftype.name == needle:
|
||||
addr = toInteger(value)
|
||||
expr = pat % (ns, ns, addr)
|
||||
res = str(gdb.parse_and_eval(expr))
|
||||
pos = res.find('"stack=[')
|
||||
if pos != -1:
|
||||
res = res[pos + 8:-2]
|
||||
res = res.replace('\\\"', '\"')
|
||||
res = res.replace('func=', 'function=')
|
||||
self.put(res)
|
||||
done = True
|
||||
break
|
||||
frame = frame.older()
|
||||
i += 1
|
||||
|
||||
frame = gdb.newest_frame()
|
||||
self.currentCallContext = None
|
||||
while i < limit and frame:
|
||||
with OutputSafer(self):
|
||||
|
@@ -249,9 +249,12 @@ void GdbMi::parseList(const QChar *&from, const QChar *to)
|
||||
}
|
||||
GdbMi child;
|
||||
child.parseResultOrValue(from, to);
|
||||
if (child.isValid())
|
||||
if (child.isValid()) {
|
||||
m_children.push_back(child);
|
||||
skipCommas(from, to);
|
||||
skipCommas(from, to);
|
||||
} else {
|
||||
++from;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3232,58 +3232,13 @@ static quint64 findJsExecutionContextAddress(const GdbMi &stackArgsResponse, con
|
||||
|
||||
void GdbEngine::loadAdditionalQmlStack()
|
||||
{
|
||||
// Scan for QV4::ExecutionContext parameter in the parameter list of a V4 call.
|
||||
DebuggerCommand cmd("-stack-list-arguments --simple-values", NeedsStop);
|
||||
cmd.callback = [this](const DebuggerResponse &response) {
|
||||
if (!response.data.isValid()) {
|
||||
showMessage(msgCannotLoadQmlStack("No stack obtained."), LogError);
|
||||
return;
|
||||
}
|
||||
const quint64 contextAddress = findJsExecutionContextAddress(response.data, qtNamespace());
|
||||
if (!contextAddress) {
|
||||
showMessage(msgCannotLoadQmlStack("The address of the JS execution context could not be found."), LogError);
|
||||
return;
|
||||
}
|
||||
// Call the debug function of QML with the context address to obtain the QML stack trace.
|
||||
DebuggerCommand cmd;
|
||||
cmd.function = "-data-evaluate-expression \"qt_v4StackTrace((QV4::ExecutionContext *)0x"
|
||||
+ QString::number(contextAddress, 16) + ")\"";
|
||||
cmd.callback = CB(handleQmlStackTrace);
|
||||
runCommand(cmd);
|
||||
};
|
||||
DebuggerCommand cmd = stackCommand(-1);
|
||||
cmd.arg("extraqml", "1");
|
||||
cmd.callback = [this](const DebuggerResponse &r) { handleStackListFrames(r, true); };
|
||||
cmd.flags = Discardable | PythonCommand;
|
||||
runCommand(cmd);
|
||||
}
|
||||
|
||||
// Scan the arguments of a stack list for the address of a QV4::ExecutionContext.
|
||||
void GdbEngine::handleQmlStackTrace(const DebuggerResponse &response)
|
||||
{
|
||||
if (!response.data.isValid()) {
|
||||
showMessage(msgCannotLoadQmlStack("No result obtained."), LogError);
|
||||
return;
|
||||
}
|
||||
// Prepend QML stack frames to existing C++ stack frames.
|
||||
QString stackData = response.data["value"].data();
|
||||
const int index = stackData.indexOf("stack=");
|
||||
if (index == -1) {
|
||||
showMessage(msgCannotLoadQmlStack("Malformed result."), LogError);
|
||||
return;
|
||||
}
|
||||
stackData.remove(0, index);
|
||||
stackData.replace("\\\"", "\"");
|
||||
GdbMi stackMi;
|
||||
stackMi.fromString(stackData);
|
||||
const int qmlFrameCount = stackMi.childCount();
|
||||
if (!qmlFrameCount) {
|
||||
showMessage(msgCannotLoadQmlStack("No stack frames obtained."), LogError);
|
||||
return;
|
||||
}
|
||||
QList<StackFrame> qmlFrames;
|
||||
qmlFrames.reserve(qmlFrameCount);
|
||||
for (int i = 0; i < qmlFrameCount; ++i)
|
||||
qmlFrames.append(StackFrame::parseFrame(stackMi.childAt(i), runParameters()));
|
||||
stackHandler()->prependFrames(qmlFrames);
|
||||
}
|
||||
|
||||
DebuggerCommand GdbEngine::stackCommand(int depth)
|
||||
{
|
||||
DebuggerCommand cmd("fetchStack");
|
||||
|
@@ -360,9 +360,8 @@ protected:
|
||||
void handleThreadNames(const DebuggerResponse &response);
|
||||
DebuggerCommand stackCommand(int depth);
|
||||
void reloadStack();
|
||||
virtual void reloadFullStack() override;
|
||||
virtual void loadAdditionalQmlStack() override;
|
||||
void handleQmlStackTrace(const DebuggerResponse &response);
|
||||
void reloadFullStack() override;
|
||||
void loadAdditionalQmlStack() override;
|
||||
int currentFrame() const;
|
||||
|
||||
//
|
||||
|
@@ -779,5 +779,11 @@ void QmlCppEngine::setActiveEngine(DebuggerEngine *engine)
|
||||
updateViews();
|
||||
}
|
||||
|
||||
void QmlCppEngine::loadAdditionalQmlStack()
|
||||
{
|
||||
if (m_cppEngine)
|
||||
m_cppEngine->loadAdditionalQmlStack();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
@@ -123,6 +123,7 @@ protected:
|
||||
|
||||
void notifyInferiorSetupOk() override;
|
||||
void notifyEngineRemoteServerRunning(const QString &, int pid) override;
|
||||
void loadAdditionalQmlStack() override;
|
||||
|
||||
private:
|
||||
void engineStateChanged(DebuggerState newState);
|
||||
|
Reference in New Issue
Block a user