diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index d4ded92165c..9ab49555f51 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -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): diff --git a/src/plugins/debugger/debuggerprotocol.cpp b/src/plugins/debugger/debuggerprotocol.cpp index f925865d35c..46f60b09541 100644 --- a/src/plugins/debugger/debuggerprotocol.cpp +++ b/src/plugins/debugger/debuggerprotocol.cpp @@ -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; + } } } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 0b6c8a4a08f..a04c99c189c 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -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 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"); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 5f8bcce0631..02a933aa14e 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -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; // diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index 5d53735b7fc..a532abe7dde 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -779,5 +779,11 @@ void QmlCppEngine::setActiveEngine(DebuggerEngine *engine) updateViews(); } +void QmlCppEngine::loadAdditionalQmlStack() +{ + if (m_cppEngine) + m_cppEngine->loadAdditionalQmlStack(); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h index 52beaa5dcbb..6fdd68ce831 100644 --- a/src/plugins/debugger/qml/qmlcppengine.h +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -123,6 +123,7 @@ protected: void notifyInferiorSetupOk() override; void notifyEngineRemoteServerRunning(const QString &, int pid) override; + void loadAdditionalQmlStack() override; private: void engineStateChanged(DebuggerState newState);