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.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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user