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:
hjk
2015-11-02 16:01:43 +01:00
parent 0d02544e67
commit 9d6c63d4d2
3 changed files with 74 additions and 82 deletions

View File

@@ -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:

View File

@@ -735,7 +735,6 @@ 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;
@@ -751,7 +750,6 @@ void GdbEngine::handleAsyncOutput(const QByteArray &asyncClass, const GdbMi &res
bp.setResponse(br);
}
}
}
} else if (asyncClass == "breakpoint-created") {
// "{bkpt={number="1",type="breakpoint",disp="del",enabled="y",
// addr="<PENDING>",pending="main",times="0",
@@ -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,10 +2549,6 @@ 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()) {
@@ -2564,7 +2557,6 @@ void GdbEngine::handleBreakInsert1(const DebuggerResponse &response, Breakpoint
} 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
// ^error,msg="mi_cmd_break_insert: Unknown option ``a''"
@@ -4321,24 +4313,25 @@ 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 (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);
}
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 {
}
// 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;

View File

@@ -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;