forked from qt-creator/qt-creator
Debugger: Move the 'break on qFatal' implementation to gdbbridge
Easier to create invisible breakpoints there. Task-number: QTCREATORBUG-15276 Change-Id: I76ffa45f9f0de5ffbc3b82a7ef9a4ddcdfff62eb Reviewed-by: Christian Stenger <christian.stenger@theqtcompany.com>
This commit is contained in:
@@ -226,6 +226,11 @@ class Dumper(DumperBase):
|
|||||||
self.qtNamespaceToReport = None
|
self.qtNamespaceToReport = None
|
||||||
self.interpreterBreakpointResolvers = []
|
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):
|
def prepare(self, args):
|
||||||
self.output = []
|
self.output = []
|
||||||
self.currentIName = ""
|
self.currentIName = ""
|
||||||
@@ -238,11 +243,6 @@ class Dumper(DumperBase):
|
|||||||
self.currentType = ReportItem()
|
self.currentType = ReportItem()
|
||||||
self.currentAddress = None
|
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.resultVarName = args.get("resultvarname", "")
|
||||||
self.expandedINames = set(args.get("expanded", []))
|
self.expandedINames = set(args.get("expanded", []))
|
||||||
self.stringCutOff = int(args.get("stringcutoff", 10000))
|
self.stringCutOff = int(args.get("stringcutoff", 10000))
|
||||||
@@ -1159,6 +1159,38 @@ class Dumper(DumperBase):
|
|||||||
# return mem.tobytes()
|
# return mem.tobytes()
|
||||||
return mem
|
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):
|
def putFields(self, value, dumpBase = True):
|
||||||
fields = value.type.fields()
|
fields = value.type.fields()
|
||||||
if self.sortStructMembers:
|
if self.sortStructMembers:
|
||||||
|
|||||||
@@ -735,21 +735,19 @@ void GdbEngine::handleAsyncOutput(const QByteArray &asyncClass, const GdbMi &res
|
|||||||
foreach (const GdbMi &bkpt, res.children()) {
|
foreach (const GdbMi &bkpt, res.children()) {
|
||||||
const QByteArray nr = bkpt["number"].data();
|
const QByteArray nr = bkpt["number"].data();
|
||||||
BreakpointResponseId rid(nr);
|
BreakpointResponseId rid(nr);
|
||||||
if (!isHiddenBreakpoint(rid)) {
|
if (nr.contains('.')) {
|
||||||
if (nr.contains('.')) {
|
// A sub-breakpoint.
|
||||||
// A sub-breakpoint.
|
BreakpointResponse sub;
|
||||||
BreakpointResponse sub;
|
updateResponse(sub, bkpt);
|
||||||
updateResponse(sub, bkpt);
|
sub.id = rid;
|
||||||
sub.id = rid;
|
sub.type = br.type;
|
||||||
sub.type = br.type;
|
bp.insertSubBreakpoint(sub);
|
||||||
bp.insertSubBreakpoint(sub);
|
} else {
|
||||||
} else {
|
// A primary breakpoint.
|
||||||
// A primary breakpoint.
|
bp = handler->findBreakpointByResponseId(rid);
|
||||||
bp = handler->findBreakpointByResponseId(rid);
|
br = bp.response();
|
||||||
br = bp.response();
|
updateResponse(br, bkpt);
|
||||||
updateResponse(br, bkpt);
|
bp.setResponse(br);
|
||||||
bp.setResponse(br);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (asyncClass == "breakpoint-created") {
|
} else if (asyncClass == "breakpoint-created") {
|
||||||
@@ -1398,7 +1396,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
|||||||
showMessage(_("INVALID STOPPED REASON"), LogWarning);
|
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.
|
// Use opportunity to update the breakpoint marker position.
|
||||||
Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid);
|
Breakpoint bp = breakHandler()->findBreakpointByResponseId(rid);
|
||||||
const BreakpointResponse &response = bp.response();
|
const BreakpointResponse &response = bp.response();
|
||||||
@@ -1415,7 +1413,6 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
|||||||
// Quickly set the location marker.
|
// Quickly set the location marker.
|
||||||
if (lineNumber && !boolSetting(OperateByInstruction)
|
if (lineNumber && !boolSetting(OperateByInstruction)
|
||||||
&& QFileInfo::exists(fullName)
|
&& QFileInfo::exists(fullName)
|
||||||
&& !isQFatalBreakpoint(rid)
|
|
||||||
&& function != "qt_v4TriggeredBreakpointHook"
|
&& function != "qt_v4TriggeredBreakpointHook"
|
||||||
&& function != "qt_qmlDebugMessageAvailable"
|
&& function != "qt_qmlDebugMessageAvailable"
|
||||||
&& language != "js")
|
&& language != "js")
|
||||||
@@ -2552,18 +2549,13 @@ void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, Breakpoint
|
|||||||
// the "main" entry. Use the "main" entry to retrieve the
|
// the "main" entry. Use the "main" entry to retrieve the
|
||||||
// already known data from the BreakpointManager, and then
|
// already known data from the BreakpointManager, and then
|
||||||
// iterate over all items to update main- and sub-data.
|
// iterate over all items to update main- and sub-data.
|
||||||
const GdbMi mainbkpt = response.data["bkpt"];
|
foreach (const GdbMi &bkpt, response.data.children())
|
||||||
const QByteArray mainnr = mainbkpt["number"].data();
|
handleBkpt(bkpt, bp);
|
||||||
const BreakpointResponseId mainrid(mainnr);
|
if (bp.needsChange()) {
|
||||||
if (!isHiddenBreakpoint(mainrid)) {
|
bp.notifyBreakpointChangeAfterInsertNeeded();
|
||||||
foreach (const GdbMi &bkpt, response.data.children())
|
changeBreakpoint(bp);
|
||||||
handleBkpt(bkpt, bp);
|
} else {
|
||||||
if (bp.needsChange()) {
|
bp.notifyBreakpointInsertOk();
|
||||||
bp.notifyBreakpointChangeAfterInsertNeeded();
|
|
||||||
changeBreakpoint(bp);
|
|
||||||
} else {
|
|
||||||
bp.notifyBreakpointInsertOk();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (response.data["msg"].data().contains("Unknown option")) {
|
} else if (response.data["msg"].data().contains("Unknown option")) {
|
||||||
// Older version of gdb don't know the -a option to set tracepoints
|
// Older version of gdb don't know the -a option to set tracepoints
|
||||||
@@ -4321,23 +4313,24 @@ void GdbEngine::finishInferiorSetup()
|
|||||||
{
|
{
|
||||||
CHECK_STATE(InferiorSetupRequested);
|
CHECK_STATE(InferiorSetupRequested);
|
||||||
|
|
||||||
if (runParameters().startMode == AttachCore) {
|
if (runParameters().startMode != AttachCore) { // No breakpoints in core files.
|
||||||
notifyInferiorSetupOk(); // No breakpoints in core files.
|
const bool onAbort = boolSetting(BreakOnAbort);
|
||||||
} else {
|
const bool onWarning = boolSetting(BreakOnWarning);
|
||||||
if (boolSetting(BreakOnAbort))
|
const bool onFatal = boolSetting(BreakOnFatal);
|
||||||
runCommand({"-break-insert -f abort"});
|
if (onAbort || onWarning || onFatal) {
|
||||||
if (boolSetting(BreakOnWarning)) {
|
DebuggerCommand cmd("createSpecialBreakpoints", PythonCommand);
|
||||||
runCommand({"-break-insert -f '" + qtNamespace() + "qWarning'", NoFlags});
|
cmd.arg("breakonabort", onAbort);
|
||||||
runCommand({"-break-insert -f '" + qtNamespace() + "QMessageLogger::warning'", NoFlags});
|
cmd.arg("breakonwarning", onWarning);
|
||||||
}
|
cmd.arg("breakonfatal", onFatal);
|
||||||
if (boolSetting(BreakOnFatal)) {
|
runCommand(cmd);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
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)
|
void GdbEngine::notifyInferiorSetupFailed(const QString &msg)
|
||||||
{
|
{
|
||||||
showStatusMessage(tr("Failed to start application:") + QLatin1Char(' ') + 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
|
bool GdbEngine::usesExecInterrupt() const
|
||||||
{
|
{
|
||||||
DebuggerStartMode mode = runParameters().startMode;
|
DebuggerStartMode mode = runParameters().startMode;
|
||||||
|
|||||||
@@ -331,8 +331,6 @@ private: ////////// View & Data Stuff //////////
|
|||||||
void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac);
|
void fetchDisassemblerByCliRangePlain(const DisassemblerAgentCookie &ac);
|
||||||
bool handleCliDisassemblerResult(const QByteArray &response, DisassemblerAgent *agent);
|
bool handleCliDisassemblerResult(const QByteArray &response, DisassemblerAgent *agent);
|
||||||
|
|
||||||
void handleBreakOnQFatal(const DebuggerResponse &response, bool continueSetup);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Source file specific stuff
|
// Source file specific stuff
|
||||||
//
|
//
|
||||||
@@ -421,14 +419,10 @@ protected:
|
|||||||
// while updating locals.
|
// while updating locals.
|
||||||
bool m_inUpdateLocals;
|
bool m_inUpdateLocals;
|
||||||
|
|
||||||
bool isQFatalBreakpoint(const BreakpointResponseId &id) const;
|
|
||||||
bool isHiddenBreakpoint(const BreakpointResponseId &id) const;
|
|
||||||
|
|
||||||
// HACK:
|
// HACK:
|
||||||
QByteArray m_currentThread;
|
QByteArray m_currentThread;
|
||||||
QString m_lastWinException;
|
QString m_lastWinException;
|
||||||
QString m_lastMissingDebugInfo;
|
QString m_lastMissingDebugInfo;
|
||||||
BreakpointResponseId m_qFatalBreakpointResponseId;
|
|
||||||
bool m_terminalTrap;
|
bool m_terminalTrap;
|
||||||
bool m_temporaryStopPending;
|
bool m_temporaryStopPending;
|
||||||
bool usesExecInterrupt() const;
|
bool usesExecInterrupt() const;
|
||||||
|
|||||||
Reference in New Issue
Block a user