forked from qt-creator/qt-creator
debugger: use the elfreader instead of external objdump
Change-Id: Ic5c5525703a6ef8924ac68e1a9ed33e411aada08 Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
@@ -388,6 +388,12 @@ DebuggerSettings::DebuggerSettings(QSettings *settings)
|
||||
item->setValue(false);
|
||||
insertItem(TargetAsync, item);
|
||||
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("WarnOnReleaseBuilds"));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(true);
|
||||
insertItem(WarnOnReleaseBuilds, item);
|
||||
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("GdbStartupCommands"));
|
||||
item->setDefaultValue(QString());
|
||||
|
||||
@@ -124,6 +124,7 @@ enum DebuggerActionCode
|
||||
AutoEnrichParameters,
|
||||
UseDynamicType,
|
||||
TargetAsync,
|
||||
WarnOnReleaseBuilds,
|
||||
|
||||
// Stack
|
||||
MaximalStackDepth,
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
#include <projectexplorer/itaskhandler.h>
|
||||
#include <texteditor/itexteditor.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/elfreader.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
@@ -2150,6 +2151,8 @@ void GdbEngine::setupEngine()
|
||||
}
|
||||
|
||||
QTC_CHECK(state() == EngineSetupRequested);
|
||||
if (debuggerCore()->boolSetting(WarnOnReleaseBuilds))
|
||||
checkForReleaseBuild();
|
||||
m_gdbAdapter->startAdapter();
|
||||
}
|
||||
|
||||
@@ -5345,6 +5348,62 @@ bool GdbEngine::attemptQuickStart() const
|
||||
return true;
|
||||
}
|
||||
|
||||
void GdbEngine::checkForReleaseBuild()
|
||||
{
|
||||
QString binary = startParameters().executable;
|
||||
Utils::ElfReader reader(binary);
|
||||
QList<QByteArray> names = reader.sectionNames();
|
||||
QString error = reader.errorString();
|
||||
|
||||
showMessage(_("EXAMINING ") + binary);
|
||||
QByteArray msg = "ELF SECTIONS: ";
|
||||
|
||||
static QList<QByteArray> 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");
|
||||
}
|
||||
|
||||
QSet<QByteArray> seen;
|
||||
foreach (const QByteArray &name, names) {
|
||||
msg.append(name);
|
||||
msg.append(' ');
|
||||
if (interesting.contains(name))
|
||||
seen.insert(name);
|
||||
}
|
||||
showMessage(_(msg));
|
||||
|
||||
if (!error.isEmpty()) {
|
||||
showMessage(_("ERROR WHILE READING ELF SECTIONS: ") + error);
|
||||
return;
|
||||
}
|
||||
if (names.isEmpty()) {
|
||||
showMessage(_("NO SECTION HEADERS FOUND"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (names.contains(".debug_info"))
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
// Factory
|
||||
//
|
||||
|
||||
@@ -403,6 +403,7 @@ private: ////////// Gdb Command Management //////////
|
||||
|
||||
QList<GdbCommand> m_commandsToRunOnTemporaryBreak;
|
||||
int gdbVersion() const { return m_gdbVersion; }
|
||||
void checkForReleaseBuild();
|
||||
|
||||
private: ////////// Gdb Output, State & Capability Handling //////////
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
QCheckBox *checkBoxAdjustBreakpointLocations;
|
||||
QCheckBox *checkBoxUseDynamicType;
|
||||
QCheckBox *checkBoxLoadGdbInit;
|
||||
QCheckBox *checkBoxWarnOnReleaseBuilds;
|
||||
QLabel *labelDangerous;
|
||||
QCheckBox *checkBoxTargetAsync;
|
||||
QCheckBox *checkBoxAutoEnrichParameters;
|
||||
@@ -146,6 +147,13 @@ public:
|
||||
"This 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."));
|
||||
|
||||
@@ -223,6 +231,7 @@ public:
|
||||
formLayout->addRow(checkBoxAdjustBreakpointLocations);
|
||||
formLayout->addRow(checkBoxUseDynamicType);
|
||||
formLayout->addRow(checkBoxLoadGdbInit);
|
||||
formLayout->addRow(checkBoxWarnOnReleaseBuilds);
|
||||
formLayout->addRow(new QLabel(QString()));
|
||||
formLayout->addRow(labelDangerous);
|
||||
formLayout->addRow(checkBoxTargetAsync);
|
||||
@@ -282,6 +291,8 @@ QWidget *GdbOptionsPage::createPage(QWidget *parent)
|
||||
m_ui->checkBoxUseDynamicType);
|
||||
m_group.insert(debuggerCore()->action(TargetAsync),
|
||||
m_ui->checkBoxTargetAsync);
|
||||
m_group.insert(debuggerCore()->action(WarnOnReleaseBuilds),
|
||||
m_ui->checkBoxWarnOnReleaseBuilds);
|
||||
m_group.insert(debuggerCore()->action(AdjustBreakpointLocations),
|
||||
m_ui->checkBoxAdjustBreakpointLocations);
|
||||
m_group.insert(debuggerCore()->action(BreakOnWarning),
|
||||
@@ -316,6 +327,7 @@ QWidget *GdbOptionsPage::createPage(QWidget *parent)
|
||||
<< sep << m_ui->groupBoxGeneral->title()
|
||||
<< sep << m_ui->checkBoxLoadGdbInit->text()
|
||||
<< sep << m_ui->checkBoxTargetAsync->text()
|
||||
<< sep << m_ui->checkBoxWarnOnReleaseBuilds->text()
|
||||
<< sep << m_ui->checkBoxUseDynamicType->text()
|
||||
<< sep << m_ui->labelGdbWatchdogTimeout->text()
|
||||
<< sep << m_ui->checkBoxEnableReverseDebugging->text()
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
@@ -100,7 +98,6 @@ void LocalPlainGdbAdapter::startAdapter()
|
||||
return;
|
||||
}
|
||||
|
||||
checkForReleaseBuild();
|
||||
m_engine->handleAdapterStarted();
|
||||
}
|
||||
|
||||
@@ -121,52 +118,6 @@ void LocalPlainGdbAdapter::shutdownAdapter()
|
||||
m_engine->notifyAdapterShutdownOk();
|
||||
}
|
||||
|
||||
void LocalPlainGdbAdapter::checkForReleaseBuild()
|
||||
{
|
||||
#ifndef Q_OS_MAC
|
||||
// There is usually no objdump on Mac, and if there is,
|
||||
// there are no .debug_info sections.
|
||||
QString objDump = _("objdump");
|
||||
// Windows: Locate objdump in the debuggee's (MinGW) environment
|
||||
if (ProjectExplorer::Abi::hostAbi().os() == ProjectExplorer::Abi::WindowsOS
|
||||
&& startParameters().environment.size()) {
|
||||
objDump = startParameters().environment.searchInPath(objDump);
|
||||
} else {
|
||||
objDump = Utils::Environment::systemEnvironment().searchInPath(objDump);
|
||||
}
|
||||
if (objDump.isEmpty()) {
|
||||
showMessage(_("Could not locate objdump command for release build check"), LogWarning);
|
||||
return;
|
||||
}
|
||||
// Quick check for a "release" build
|
||||
QProcess proc;
|
||||
QStringList args;
|
||||
args.append(_("-h"));
|
||||
args.append(_("-j"));
|
||||
args.append(_(".debug_info"));
|
||||
args.append(startParameters().executable);
|
||||
proc.start(objDump, args);
|
||||
proc.closeWriteChannel();
|
||||
if (!proc.waitForStarted()) {
|
||||
showMessage(_("OBJDUMP PROCESS COULD NOT BE STARTED. "
|
||||
"RELEASE BUILD CHECK WILL FAIL"));
|
||||
return;
|
||||
}
|
||||
proc.waitForFinished();
|
||||
QByteArray ba = proc.readAllStandardOutput();
|
||||
// This should yield something like
|
||||
// "debuggertest: file format elf32-i386\n\n"
|
||||
// "Sections:\nIdx Name Size VMA LMA File off Algn\n"
|
||||
// "30 .debug_info 00087d36 00000000 00000000 0006bbd5 2**0\n"
|
||||
// " CONTENTS, READONLY, DEBUGGING"
|
||||
if (ba.contains("Sections:") && !ba.contains(".debug_info")) {
|
||||
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."));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LocalPlainGdbAdapter::interruptInferior()
|
||||
{
|
||||
interruptLocalInferior(m_engine->inferiorPid());
|
||||
|
||||
Reference in New Issue
Block a user