diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 213cede8e59..fec5102627f 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -226,6 +226,11 @@ class Dumper(DumperBase): self.qtNamespaceToReport = None self.interpreterBreakpointResolvers = [] + # The guess does not need to be updated during a fetchVariables() + # as the result is fixed during that time (ignoring "active" + # dumpers causing loading of shared objects etc). + self.currentQtNamespaceGuess = None + def prepare(self, args): self.output = [] self.currentIName = "" @@ -238,11 +243,6 @@ class Dumper(DumperBase): self.currentType = ReportItem() self.currentAddress = None - # The guess does not need to be updated during a fetchVariables() - # as the result is fixed during that time (ignoring "active" - # dumpers causing loading of shared objects etc). - self.currentQtNamespaceGuess = None - self.resultVarName = args.get("resultvarname", "") self.expandedINames = set(args.get("expanded", [])) self.stringCutOff = int(args.get("stringcutoff", 10000)) @@ -1159,6 +1159,38 @@ class Dumper(DumperBase): # return mem.tobytes() return mem + def createSpecialBreakpoints(self, args): + self.specialBreakpoints = [] + def newSpecial(spec): + class SpecialBreakpoint(gdb.Breakpoint): + def __init__(self, spec): + super(SpecialBreakpoint, self).\ + __init__(spec, gdb.BP_BREAKPOINT, internal=True) + self.spec = spec + + def stop(self): + print("Breakpoint on '%s' hit." % self.spec) + return True + return SpecialBreakpoint(spec) + + # FIXME: ns is accessed too early. gdb.Breakpoint() has no + # 'rbreak' replacement, and breakpoints created with + # 'gdb.execute("rbreak...") cannot be made invisible. + # So let's ignore the existing of namespaced builds for this + # fringe feature here for now. + ns = self.qtNamespace() + if args.get('breakonabort', 0): + self.specialBreakpoints.append(newSpecial("abort")) + + if args.get('breakonwarning', 0): + self.specialBreakpoints.append(newSpecial(ns + "qWarning")) + self.specialBreakpoints.append(newSpecial(ns + "QMessageLogger::warning")) + + if args.get('breakonfatal', 0): + self.specialBreakpoints.append(newSpecial(ns + "qFatal")) + self.specialBreakpoints.append(newSpecial(ns + "QMessageLogger::fatal")) + + def putFields(self, value, dumpBase = True): fields = value.type.fields() if self.sortStructMembers: diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index c12ed2ece84..1dbe494d462 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -735,21 +735,19 @@ void GdbEngine::handleAsyncOutput(const QByteArray &asyncClass, const GdbMi &res foreach (const GdbMi &bkpt, res.children()) { const QByteArray nr = bkpt["number"].data(); BreakpointResponseId rid(nr); - if (!isHiddenBreakpoint(rid)) { - if (nr.contains('.')) { - // A sub-breakpoint. - BreakpointResponse sub; - updateResponse(sub, bkpt); - sub.id = rid; - sub.type = br.type; - bp.insertSubBreakpoint(sub); - } else { - // A primary breakpoint. - bp = handler->findBreakpointByResponseId(rid); - br = bp.response(); - updateResponse(br, bkpt); - bp.setResponse(br); - } + if (nr.contains('.')) { + // A sub-breakpoint. + BreakpointResponse sub; + updateResponse(sub, bkpt); + sub.id = rid; + sub.type = br.type; + bp.insertSubBreakpoint(sub); + } else { + // A primary breakpoint. + bp = handler->findBreakpointByResponseId(rid); + br = bp.response(); + updateResponse(br, bkpt); + bp.setResponse(br); } } } else if (asyncClass == "breakpoint-created") { @@ -1398,7 +1396,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) showMessage(_("INVALID STOPPED REASON"), LogWarning); } - if (rid.isValid() && frame.isValid() && !isQFatalBreakpoint(rid)) { + if (rid.isValid() && frame.isValid()) { // Use opportunity to update the breakpoint marker position. Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid); const BreakpointResponse &response = bp.response(); @@ -1415,7 +1413,6 @@ void GdbEngine::handleStopResponse(const GdbMi &data) // Quickly set the location marker. if (lineNumber && !boolSetting(OperateByInstruction) && QFileInfo::exists(fullName) - && !isQFatalBreakpoint(rid) && function != "qt_v4TriggeredBreakpointHook" && function != "qt_qmlDebugMessageAvailable" && language != "js") @@ -2552,18 +2549,13 @@ void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, Breakpoint // the "main" entry. Use the "main" entry to retrieve the // already known data from the BreakpointManager, and then // iterate over all items to update main- and sub-data. - const GdbMi mainbkpt = response.data["bkpt"]; - const QByteArray mainnr = mainbkpt["number"].data(); - const BreakpointResponseId mainrid(mainnr); - if (!isHiddenBreakpoint(mainrid)) { - foreach (const GdbMi &bkpt, response.data.children()) - handleBkpt(bkpt, bp); - if (bp.needsChange()) { - bp.notifyBreakpointChangeAfterInsertNeeded(); - changeBreakpoint(bp); - } else { - bp.notifyBreakpointInsertOk(); - } + foreach (const GdbMi &bkpt, response.data.children()) + handleBkpt(bkpt, bp); + if (bp.needsChange()) { + bp.notifyBreakpointChangeAfterInsertNeeded(); + changeBreakpoint(bp); + } else { + bp.notifyBreakpointInsertOk(); } } else if (response.data["msg"].data().contains("Unknown option")) { // Older version of gdb don't know the -a option to set tracepoints @@ -4321,23 +4313,24 @@ void GdbEngine::finishInferiorSetup() { CHECK_STATE(InferiorSetupRequested); - if (runParameters().startMode == AttachCore) { - notifyInferiorSetupOk(); // No breakpoints in core files. - } else { - if (boolSetting(BreakOnAbort)) - runCommand({"-break-insert -f abort"}); - if (boolSetting(BreakOnWarning)) { - runCommand({"-break-insert -f '" + qtNamespace() + "qWarning'", NoFlags}); - runCommand({"-break-insert -f '" + qtNamespace() + "QMessageLogger::warning'", NoFlags}); - } - if (boolSetting(BreakOnFatal)) { - auto cb = [this](const DebuggerResponse &r) { handleBreakOnQFatal(r, false); }; - runCommand({"-break-insert -f '" + qtNamespace() + "qFatal'", NoFlags, cb}); - runCommand({"-break-insert -f '" + qtNamespace() + "QMessageLogger::fatal'", NoFlags, cb}); - } else { - notifyInferiorSetupOk(); + if (runParameters().startMode != AttachCore) { // No breakpoints in core files. + const bool onAbort = boolSetting(BreakOnAbort); + const bool onWarning = boolSetting(BreakOnWarning); + const bool onFatal = boolSetting(BreakOnFatal); + if (onAbort || onWarning || onFatal) { + DebuggerCommand cmd("createSpecialBreakpoints", PythonCommand); + 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. + notifyInferiorSetupOk(); } void GdbEngine::handleDebugInfoLocation(const DebuggerResponse &response) @@ -4354,23 +4347,6 @@ void GdbEngine::handleDebugInfoLocation(const DebuggerResponse &response) } } -void GdbEngine::handleBreakOnQFatal(const DebuggerResponse &response, bool continueSetup) -{ - if (response.resultClass == ResultDone) { - GdbMi bkpt = response.data["bkpt"]; - GdbMi number = bkpt["number"]; - BreakpointResponseId rid(number.data()); - if (rid.isValid()) { - m_qFatalBreakpointResponseId = rid; - runCommand({"-break-commands " + number.data() + " return", NoFlags}); - } - } - - // Continue setup. - if (continueSetup) - notifyInferiorSetupOk(); -} - void GdbEngine::notifyInferiorSetupFailed(const QString &msg) { showStatusMessage(tr("Failed to start application:") + QLatin1Char(' ') + msg); @@ -4431,16 +4407,6 @@ void GdbEngine::resetCommandQueue() } } -bool GdbEngine::isQFatalBreakpoint(const BreakpointResponseId &id) const -{ - return id.isValid() && m_qFatalBreakpointResponseId == id; -} - -bool GdbEngine::isHiddenBreakpoint(const BreakpointResponseId &id) const -{ - return isQFatalBreakpoint(id); -} - bool GdbEngine::usesExecInterrupt() const { DebuggerStartMode mode = runParameters().startMode; diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 7083c11aa87..4c08219ddfa 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -331,8 +331,6 @@ private: ////////// View & Data Stuff ////////// void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac); bool handleCliDisassemblerResult(const QByteArray &response, DisassemblerAgent *agent); - void handleBreakOnQFatal(const DebuggerResponse &response, bool continueSetup); - // // Source file specific stuff // @@ -421,14 +419,10 @@ protected: // while updating locals. bool m_inUpdateLocals; - bool isQFatalBreakpoint(const BreakpointResponseId &id) const; - bool isHiddenBreakpoint(const BreakpointResponseId &id) const; - // HACK: QByteArray m_currentThread; QString m_lastWinException; QString m_lastMissingDebugInfo; - BreakpointResponseId m_qFatalBreakpointResponseId; bool m_terminalTrap; bool m_temporaryStopPending; bool usesExecInterrupt() const;