Debugger: Move initial GDB breakpoint settings after target setup

While GDB can handle breakpoints set before specifying an executable
fine, it stresses the machinery unnecessarily and fails in corner cases
("wrong" dynamic loader etc). We can avoid most of that by moving the
breakpoint setting to a later point in the process.

Change-Id: I0450a0e43a81c80bfdfefb7b67f6799042e0ec26
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2021-01-05 17:56:46 +01:00
parent 8753889c63
commit 13c9b42a21
2 changed files with 31 additions and 26 deletions

View File

@@ -3855,33 +3855,16 @@ void GdbEngine::prepareForRestart()
void GdbEngine::handleInferiorPrepared()
{
const DebuggerRunParameters &rp = runParameters();
CHECK_STATE(EngineSetupRequested);
const DebuggerRunParameters &rp = runParameters();
if (!rp.commandsAfterConnect.isEmpty()) {
const QString commands = expand(rp.commandsAfterConnect);
for (const QString &command : commands.split('\n'))
runCommand({command, NativeCommand});
}
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");
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.
claimInitialBreakpoints();
notifyEngineSetupOk();
runEngine();
}
@@ -4039,6 +4022,34 @@ bool GdbEngine::isTermEngine() const
return !isCoreEngine() && !isAttachEngine() && !isRemoteEngine() && terminal();
}
void GdbEngine::claimInitialBreakpoints()
{
CHECK_STATE(EngineSetupRequested);
const DebuggerRunParameters &rp = runParameters();
if (rp.startMode != AttachCore) {
showStatusMessage(tr("Setting breakpoints..."));
showMessage(tr("Setting breakpoints..."));
BreakpointManager::claimBreakpointsForEngine(this);
const bool onAbort = boolSetting(BreakOnAbort);
const bool onWarning = boolSetting(BreakOnWarning);
const bool onFatal = boolSetting(BreakOnFatal);
if (onAbort || onWarning || onFatal) {
DebuggerCommand cmd("createSpecialBreakpoints");
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.
}
void GdbEngine::setupInferior()
{
CHECK_STATE(EngineSetupRequested);
@@ -4049,13 +4060,6 @@ void GdbEngine::setupInferior()
if (rp.breakOnMain)
runCommand({"tbreak " + mainFunction()});
// Initial attempt to set breakpoints.
if (rp.startMode != AttachCore) {
showStatusMessage(tr("Setting breakpoints..."));
showMessage(tr("Setting breakpoints..."));
BreakpointManager::claimBreakpointsForEngine(this);
}
if (rp.startMode == AttachToRemoteProcess) {
handleInferiorPrepared();

View File

@@ -418,6 +418,7 @@ private: ////////// General Interface //////////
QString mainFunction() const;
void setupInferior();
void claimInitialBreakpoints();
Utils::QtcProcess m_gdbProc;
OutputCollector m_outputCollector;