diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index 512025ec2b3..5de162e0adc 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -93,6 +93,11 @@ CommonOptionsPageWidget::CommonOptionsPageWidget checkBoxRegisterForPostMortem->setToolTip(tr("Register Qt Creator for debugging crashed applications.")); checkBoxRegisterForPostMortem->setText(tr("Use Qt Creator for post-mortem debugging")); + checkBoxWarnOnReleaseBuilds = new QCheckBox(behaviorBox); + checkBoxWarnOnReleaseBuilds->setText(tr("Warn when debugging \"Release\" builds")); + checkBoxWarnOnReleaseBuilds->setToolTip(tr("Show a warning when starting the debugger " + "on a binary with insufficient debug information.")); + labelMaximalStackDepth = new QLabel(tr("Maximum stack depth:"), behaviorBox); spinBoxMaximalStackDepth = new QSpinBox(behaviorBox); @@ -127,6 +132,7 @@ CommonOptionsPageWidget::CommonOptionsPageWidget gridLayout->addWidget(checkBoxCloseBuffersOnExit, 2, 0, 1, 1); gridLayout->addWidget(checkBoxBringToForegroundOnInterrrupt, 3, 0, 1, 1); gridLayout->addWidget(checkBoxBreakpointsFullPath, 4, 0, 1, 1); + gridLayout->addWidget(checkBoxWarnOnReleaseBuilds, 5, 0, 1, 1); gridLayout->addLayout(horizontalLayout, 6, 0, 1, 2); gridLayout->addWidget(checkBoxFontSizeFollowsEditor, 0, 1, 1, 1); @@ -160,6 +166,8 @@ CommonOptionsPageWidget::CommonOptionsPageWidget checkBoxBringToForegroundOnInterrrupt); m_group->insert(dc->action(ShowQmlObjectTree), checkBoxShowQmlObjectTree); + m_group->insert(dc->action(WarnOnReleaseBuilds), + checkBoxWarnOnReleaseBuilds); m_group->insert(dc->action(FontSizeFollowsEditor), checkBoxFontSizeFollowsEditor); m_group->insert(dc->action(AutoDerefPointers), 0); @@ -207,7 +215,8 @@ QString CommonOptionsPageWidget::searchKeyWords() const << sep << checkBoxSwitchModeOnExit->text() << sep << labelMaximalStackDepth->text() << sep << checkBoxBringToForegroundOnInterrrupt->text() - << sep << checkBoxShowQmlObjectTree->text(); + << sep << checkBoxShowQmlObjectTree->text() + << sep << checkBoxWarnOnReleaseBuilds->text(); if (Utils::HostOsInfo::isWindowsHost()) stream << sep << checkBoxRegisterForPostMortem->text(); diff --git a/src/plugins/debugger/commonoptionspage.h b/src/plugins/debugger/commonoptionspage.h index f3549969ae8..4b77509b021 100644 --- a/src/plugins/debugger/commonoptionspage.h +++ b/src/plugins/debugger/commonoptionspage.h @@ -74,6 +74,7 @@ private: QCheckBox *checkBoxShowQmlObjectTree; QCheckBox *checkBoxBreakpointsFullPath; QCheckBox *checkBoxRegisterForPostMortem; + QCheckBox *checkBoxWarnOnReleaseBuilds; QLabel *labelMaximalStackDepth; QLabel *labelMaximalStringLength; QSpinBox *spinBoxMaximalStackDepth; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index e962e949410..08d006fb2bc 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -37,10 +37,11 @@ #include "debuggerstringutils.h" #include "debuggerstartparameters.h" -#include "memoryagent.h" -#include "disassembleragent.h" #include "breakhandler.h" +#include "disassembleragent.h" +#include "memoryagent.h" #include "moduleshandler.h" +#include "peutils.h" #include "registerhandler.h" #include "snapshothandler.h" #include "sourcefileshandler.h" @@ -60,6 +61,7 @@ #include #include +#include #include #include #include @@ -760,6 +762,7 @@ void DebuggerEnginePrivate::doSetupEngine() { m_engine->showMessage(_("CALL: SETUP ENGINE")); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << m_engine << state()); + m_engine->checkForReleaseBuild(m_startParameters); m_engine->setupEngine(); } @@ -1789,6 +1792,95 @@ void DebuggerEngine::setStateDebugging(bool on) d->m_isStateDebugging = on; } +void DebuggerEngine::checkForReleaseBuild(const DebuggerStartParameters &sp) +{ + if (!debuggerCore()->boolSetting(WarnOnReleaseBuilds) || !(sp.languages & CppLanguage)) + return; + QString binary = sp.executable; + if (binary.isEmpty()) + return; + + QString detailedWarning; + switch (sp.toolChainAbi.binaryFormat()) { + case ProjectExplorer::Abi::PEFormat: { + if (sp.masterEngineType != CdbEngineType) + return; + if (!binary.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) + binary.append(QLatin1String(".exe")); + QString errorMessage; + QStringList rc; + if (getPDBFiles(binary, &rc, &errorMessage) && !rc.isEmpty()) + return; + if (!errorMessage.isEmpty()) { + detailedWarning.append(tr("\n").append(errorMessage)); + } + break; + } + case ProjectExplorer::Abi::ElfFormat: { + + Utils::ElfReader reader(binary); + Utils::ElfData elfData = reader.readHeaders(); + QString error = reader.errorString(); + + debuggerCore()->showMessage(_("EXAMINING ") + binary, LogDebug); + QByteArray msg = "ELF SECTIONS: "; + + static QList interesting; + if (interesting.isEmpty()) { + interesting.append(".debug_info"); + interesting.append(".debug_abbrev"); + interesting.append(".debug_line"); + interesting.append(".debug_str"); + interesting.append(".debug_loc"); + interesting.append(".debug_range"); + interesting.append(".gdb_index"); + interesting.append(".note.gnu.build-id"); + interesting.append(".gnu.hash"); + interesting.append(".gnu_debuglink"); + } + + QSet seen; + foreach (const Utils::ElfSectionHeader &header, elfData.sectionHeaders) { + msg.append(header.name); + msg.append(' '); + if (interesting.contains(header.name)) + seen.insert(header.name); + } + debuggerCore()->showMessage(_(msg), LogDebug); + + if (!error.isEmpty()) { + debuggerCore()->showMessage(_("ERROR WHILE READING ELF SECTIONS: ") + error, + LogDebug); + return; + } + + if (elfData.sectionHeaders.isEmpty()) { + debuggerCore()->showMessage(_("NO SECTION HEADERS FOUND. IS THIS AN EXECUTABLE?"), + LogDebug); + return; + } + + // Note: .note.gnu.build-id also appears in regular release builds. + // bool hasBuildId = elfData.indexOf(".note.gnu.build-id") >= 0; + bool hasEmbeddedInfo = elfData.indexOf(".debug_info") >= 0; + bool hasLink = elfData.indexOf(".gnu_debuglink") >= 0; + if (hasEmbeddedInfo || hasLink) + return; + + foreach (const QByteArray &name, interesting) { + const QString found = seen.contains(name) ? tr("Found.") : tr("Not Found."); + detailedWarning.append(tr("\nSection %1: %2").arg(_(name)).arg(found)); + } + break; + } + default: + return; + } + showMessageBox(QMessageBox::Information, tr("Warning"), + tr("This does not seem to be a \"Debug\" build.\n" + "Setting breakpoints by file name and line number may fail.\n").append(detailedWarning)); +} + void DebuggerEngine::handleAutoTests() { d->handleAutoTests(); diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 64ec1ef9e6a..9f0964141f9 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -385,6 +385,8 @@ protected: bool isStateDebugging() const; void setStateDebugging(bool on); + static void checkForReleaseBuild(const DebuggerStartParameters& sp); + virtual void setupSlaveInferior(); virtual void setupSlaveEngine(); virtual void runSlaveEngine(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 59d70c6035c..5c90fdb053d 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4831,9 +4831,6 @@ void GdbEngine::startGdb(const QStringList &args) typedef GlobalDebuggerOptions::SourcePathMap SourcePathMap; typedef SourcePathMap::const_iterator SourcePathMapIterator; - if (debuggerCore()->boolSetting(WarnOnReleaseBuilds)) - checkForReleaseBuild(); - showStatusMessage(tr("Setting up inferior...")); // Addint executable to modules list. @@ -5348,70 +5345,6 @@ bool GdbEngine::attemptQuickStart() const return true; } -void GdbEngine::checkForReleaseBuild() -{ - const QString binary = startParameters().executable; - if (binary.isEmpty()) - return; - ElfReader reader(binary); - ElfData elfData = reader.readHeaders(); - QString error = reader.errorString(); - - showMessage(_("EXAMINING ") + binary); - QByteArray msg = "ELF SECTIONS: "; - - static QList interesting; - if (interesting.isEmpty()) { - interesting.append(".debug_info"); - interesting.append(".debug_abbrev"); - interesting.append(".debug_line"); - interesting.append(".debug_str"); - interesting.append(".debug_loc"); - interesting.append(".debug_range"); - interesting.append(".gdb_index"); - interesting.append(".note.gnu.build-id"); - interesting.append(".gnu.hash"); - interesting.append(".gnu_debuglink"); - } - - QSet seen; - foreach (const ElfSectionHeader &header, elfData.sectionHeaders) { - msg.append(header.name); - msg.append(' '); - if (interesting.contains(header.name)) - seen.insert(header.name); - } - showMessage(_(msg)); - - if (!error.isEmpty()) { - showMessage(_("ERROR WHILE READING ELF SECTIONS: ") + error); - return; - } - - if (elfData.sectionHeaders.isEmpty()) { - showMessage(_("NO SECTION HEADERS FOUND. IS THIS AN EXECUTABLE?")); - return; - } - - // Note: .note.gnu.build-id also appears in regular release builds. - // bool hasBuildId = elfData.indexOf(".note.gnu.build-id") >= 0; - bool hasEmbeddedInfo = elfData.indexOf(".debug_info") >= 0; - bool hasLink = elfData.indexOf(".gnu_debuglink") >= 0; - if (hasEmbeddedInfo || hasLink) - return; - - QString warning; - warning = tr("This does not seem to be a \"Debug\" build.\n" - "Setting breakpoints by file name and line number may fail.\n"); - - foreach (const QByteArray &name, interesting) { - QString found = seen.contains(name) ? tr("Found.") : tr("Not Found."); - warning.append(tr("\nSection %1: %2").arg(_(name)).arg(found)); - } - - showMessageBox(QMessageBox::Information, tr("Warning"), warning); -} - void GdbEngine::write(const QByteArray &data) { gdbProc()->write(data); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index b70d9e47565..e64a3310c1d 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -368,7 +368,6 @@ private: QList m_commandsToRunOnTemporaryBreak; int gdbVersion() const { return m_gdbVersion; } - void checkForReleaseBuild(); private: ////////// Gdb Output, State & Capability Handling ////////// protected: diff --git a/src/plugins/debugger/gdb/gdboptionspage.cpp b/src/plugins/debugger/gdb/gdboptionspage.cpp index 014db0cf010..bb38d730f9c 100644 --- a/src/plugins/debugger/gdb/gdboptionspage.cpp +++ b/src/plugins/debugger/gdb/gdboptionspage.cpp @@ -67,7 +67,6 @@ public: QCheckBox *checkBoxAdjustBreakpointLocations; QCheckBox *checkBoxUseDynamicType; QCheckBox *checkBoxLoadGdbInit; - QCheckBox *checkBoxWarnOnReleaseBuilds; QLabel *labelDangerous; QCheckBox *checkBoxTargetAsync; QCheckBox *checkBoxAutoEnrichParameters; @@ -158,13 +157,6 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent) "Allows or inhibits reading the user's default\n" ".gdbinit file on debugger startup.")); - checkBoxWarnOnReleaseBuilds = new QCheckBox(groupBoxGeneral); - checkBoxWarnOnReleaseBuilds->setText(GdbOptionsPage::tr( - "Warn when debugging \"Release\" builds")); - checkBoxWarnOnReleaseBuilds->setToolTip(GdbOptionsPage::tr( - "Show a warning when starting the debugger " - "on a binary with insufficient debug information.")); - labelDangerous = new QLabel(GdbOptionsPage::tr( "The options below should be used with care.")); labelDangerous->setToolTip(GdbOptionsPage::tr( @@ -292,7 +284,6 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent) formLayout->addRow(checkBoxAdjustBreakpointLocations); formLayout->addRow(checkBoxUseDynamicType); formLayout->addRow(checkBoxLoadGdbInit); - formLayout->addRow(checkBoxWarnOnReleaseBuilds); formLayout->addRow(checkBoxIntelFlavor); formLayout->addRow(labelDangerous); formLayout->addRow(checkBoxTargetAsync); @@ -335,7 +326,6 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent) group.insert(dc->action(AutoEnrichParameters), checkBoxAutoEnrichParameters); group.insert(dc->action(UseDynamicType), checkBoxUseDynamicType); group.insert(dc->action(TargetAsync), checkBoxTargetAsync); - group.insert(dc->action(WarnOnReleaseBuilds), checkBoxWarnOnReleaseBuilds); group.insert(dc->action(AdjustBreakpointLocations), checkBoxAdjustBreakpointLocations); group.insert(dc->action(BreakOnWarning), checkBoxBreakOnWarning); group.insert(dc->action(BreakOnFatal), checkBoxBreakOnFatal); @@ -360,7 +350,6 @@ GdbOptionsPageWidget::GdbOptionsPageWidget(QWidget *parent) << sep << groupBoxGeneral->title() << sep << checkBoxLoadGdbInit->text() << sep << checkBoxTargetAsync->text() - << sep << checkBoxWarnOnReleaseBuilds->text() << sep << checkBoxUseDynamicType->text() << sep << labelGdbWatchdogTimeout->text() << sep << checkBoxEnableReverseDebugging->text() diff --git a/src/plugins/debugger/gdb/localplaingdbadapter.h b/src/plugins/debugger/gdb/localplaingdbadapter.h index 7b7a48edc66..ad34f6944d5 100644 --- a/src/plugins/debugger/gdb/localplaingdbadapter.h +++ b/src/plugins/debugger/gdb/localplaingdbadapter.h @@ -62,7 +62,6 @@ private: QByteArray execFilePath() const; QByteArray toLocalEncoding(const QString &s) const; QString fromLocalEncoding(const QByteArray &b) const; - void checkForReleaseBuild(); OutputCollector m_outputCollector; LocalGdbProcess m_gdbProc;