diff --git a/src/libs/utils/elfreader.cpp b/src/libs/utils/elfreader.cpp index 25bb35cf5b2..b48ae2a7a5d 100644 --- a/src/libs/utils/elfreader.cpp +++ b/src/libs/utils/elfreader.cpp @@ -101,33 +101,23 @@ static void parseProgramHeader(const uchar *s, ElfProgramHeader *sh, const ElfDa sh->memsz = getWord(s, context); } -class ElfMapper +ElfMapper::ElfMapper(const ElfReader *reader) : file(reader->m_binary) {} + +bool ElfMapper::map() { -public: - ElfMapper(const ElfReader *reader) : file(reader->m_binary) {} + if (!file.open(QIODevice::ReadOnly)) + return false; - bool map() - { - if (!file.open(QIODevice::ReadOnly)) - return false; - - fdlen = file.size(); - ustart = file.map(0, fdlen); - if (ustart == 0) { - // Try reading the data into memory instead. - raw = file.readAll(); - start = raw.constData(); - fdlen = raw.size(); - } - return true; + fdlen = file.size(); + ustart = file.map(0, fdlen); + if (ustart == 0) { + // Try reading the data into memory instead. + raw = file.readAll(); + start = raw.constData(); + fdlen = raw.size(); } - -public: - QFile file; - QByteArray raw; - union { const char *start; const uchar *ustart; }; - quint64 fdlen; -}; + return true; +} ElfReader::ElfReader(const QString &binary) : m_binary(binary) @@ -298,19 +288,22 @@ ElfReader::Result ElfReader::readIt() return Ok; } -QByteArray ElfReader::readSection(const QByteArray &name) +QSharedPointer ElfReader::readSection(const QByteArray &name) { + QSharedPointer mapper; readIt(); int i = m_elfData.indexOf(name); if (i == -1) - return QByteArray(); + return mapper; - ElfMapper mapper(this); - if (!mapper.map()) - return QByteArray(); + mapper.reset(new ElfMapper(this)); + if (!mapper->map()) + return mapper; const ElfSectionHeader §ion = m_elfData.sectionHeaders.at(i); - return QByteArray(mapper.start + section.offset, section.size); + mapper->start += section.offset; + mapper->fdlen = section.size; + return mapper; } static QByteArray cutout(const char *s) diff --git a/src/libs/utils/elfreader.h b/src/libs/utils/elfreader.h index 4692f0384a5..67d0539de31 100644 --- a/src/libs/utils/elfreader.h +++ b/src/libs/utils/elfreader.h @@ -32,12 +32,17 @@ #include "utils_global.h" +#include #include +#include #include #include +#include namespace Utils { +class ElfMapper; + enum ElfProgramHeaderType { Elf_PT_NULL = 0, @@ -161,7 +166,7 @@ public: enum Result { Ok, NotElf, Corrupt }; ElfData readHeaders(); - QByteArray readSection(const QByteArray §ionName); + QSharedPointer readSection(const QByteArray §ionName); QString errorString() const { return m_errorString; } QByteArray readCoreName(bool *isCore); @@ -174,6 +179,19 @@ private: ElfData m_elfData; }; +class QTCREATOR_UTILS_EXPORT ElfMapper +{ +public: + ElfMapper(const ElfReader *reader); + bool map(); + +public: + QFile file; + QByteArray raw; + union { const char *start; const uchar *ustart; }; + quint64 fdlen; +}; + } // namespace Utils #endif // UTILS_ELFREADER_H diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index 87f0229de19..34263c3e699 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -230,13 +230,24 @@ CommonOptionsPageWidget::CommonOptionsPageWidget GlobalDebuggerOptions CommonOptionsPageWidget::globalOptions() const { GlobalDebuggerOptions o; - o.sourcePathMap = sourcesMappingWidget->sourcePathMap(); + SourcePathMap allPathMap = sourcesMappingWidget->sourcePathMap(); + for (auto it = allPathMap.begin(), end = allPathMap.end(); it != end; ++it) { + const QString key = it.key(); + if (key.startsWith(QLatin1Char('('))) + o.sourcePathRegExpMap.append(qMakePair(QRegExp(key), it.value())); + else + o.sourcePathMap.insert(key, it.value()); + } return o; } void CommonOptionsPageWidget::setGlobalOptions(const GlobalDebuggerOptions &go) { - sourcesMappingWidget->setSourcePathMap(go.sourcePathMap); + SourcePathMap allPathMap = go.sourcePathMap; + foreach (auto regExpMap, go.sourcePathRegExpMap) + allPathMap.insert(regExpMap.first.pattern(), regExpMap.second); + + sourcesMappingWidget->setSourcePathMap(allPathMap); } /////////////////////////////////////////////////////////////////////// diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index d39f3117113..190b014c28c 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -55,7 +55,7 @@ void GlobalDebuggerOptions::toSettings() const { QSettings *s = Core::ICore::settings(); s->beginWriteArray(QLatin1String(sourcePathMappingArrayNameC)); - if (!sourcePathMap.isEmpty()) { + if (!sourcePathMap.isEmpty() || !sourcePathRegExpMap.isEmpty()) { const QString sourcePathMappingSourceKey = QLatin1String(sourcePathMappingSourceKeyC); const QString sourcePathMappingTargetKey = QLatin1String(sourcePathMappingTargetKeyC); int i = 0; @@ -66,6 +66,13 @@ void GlobalDebuggerOptions::toSettings() const s->setValue(sourcePathMappingSourceKey, it.key()); s->setValue(sourcePathMappingTargetKey, it.value()); } + for (auto it = sourcePathRegExpMap.constBegin(), cend = sourcePathRegExpMap.constEnd(); + it != cend; + ++it, ++i) { + s->setArrayIndex(i); + s->setValue(sourcePathMappingSourceKey, it->first.pattern()); + s->setValue(sourcePathMappingTargetKey, it->second); + } } s->endArray(); } @@ -79,8 +86,12 @@ void GlobalDebuggerOptions::fromSettings() const QString sourcePathMappingTargetKey = QLatin1String(sourcePathMappingTargetKeyC); for (int i = 0; i < count; ++i) { s->setArrayIndex(i); - sourcePathMap.insert(s->value(sourcePathMappingSourceKey).toString(), - s->value(sourcePathMappingTargetKey).toString()); + const QString key = s->value(sourcePathMappingSourceKey).toString(); + const QString value = s->value(sourcePathMappingTargetKey).toString(); + if (key.startsWith(QLatin1Char('('))) + sourcePathRegExpMap.append(qMakePair(QRegExp(key), value)); + else + sourcePathMap.insert(key, value); } } s->endArray(); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 9a33116a36a..9998d73bf03 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -33,6 +33,7 @@ #include #include #include +#include namespace Utils { class SavedAction; } @@ -40,6 +41,7 @@ namespace Debugger { namespace Internal { typedef QMap SourcePathMap; +typedef QVector > SourcePathRegExpMap; // Global debugger options that are not stored as saved action. class GlobalDebuggerOptions @@ -48,11 +50,17 @@ public: void toSettings() const; void fromSettings(); bool operator==(const GlobalDebuggerOptions &rhs) const - { return sourcePathMap == rhs.sourcePathMap; } + { + return sourcePathMap == rhs.sourcePathMap + && sourcePathRegExpMap == rhs.sourcePathRegExpMap; + } bool operator!=(const GlobalDebuggerOptions &rhs) const - { return sourcePathMap != rhs.sourcePathMap; } + { + return !(*this == rhs); + } SourcePathMap sourcePathMap; + SourcePathRegExpMap sourcePathRegExpMap; }; class DebuggerSettings : public QObject diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index de3d8130a84..93ae9aeba1f 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -705,7 +705,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->validateExecutable(&m_startParameters); m_engine->setupEngine(); } @@ -1749,18 +1749,19 @@ void DebuggerEngine::setStateDebugging(bool on) d->m_isStateDebugging = on; } -void DebuggerEngine::checkForReleaseBuild(const DebuggerStartParameters &sp) +void DebuggerEngine::validateExecutable(DebuggerStartParameters *sp) { - if (!boolSetting(WarnOnReleaseBuilds) || !(sp.languages & CppLanguage)) + if (sp->languages == QmlLanguage) return; - QString binary = sp.executable; + QString binary = sp->executable; if (binary.isEmpty()) return; + const bool warnOnRelease = boolSetting(WarnOnReleaseBuilds); QString detailedWarning; - switch (sp.toolChainAbi.binaryFormat()) { + switch (sp->toolChainAbi.binaryFormat()) { case ProjectExplorer::Abi::PEFormat: { - if (sp.masterEngineType != CdbEngineType) + if (!warnOnRelease || (sp->masterEngineType != CdbEngineType)) return; if (!binary.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) binary.append(QLatin1String(".exe")); @@ -1822,6 +1823,36 @@ void DebuggerEngine::checkForReleaseBuild(const DebuggerStartParameters &sp) // 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) { + if (QSharedPointer mapper = reader.readSection(".debug_str")) { + QSharedPointer options = debuggerCore()->globalDebuggerOptions(); + SourcePathRegExpMap globalRegExpSourceMap = options->sourcePathRegExpMap; + const char *str = mapper->start; + const char *limit = str + mapper->fdlen; + while (str < limit) { + QString string = QString::fromUtf8(str); + auto itExp = globalRegExpSourceMap.begin(); + auto itEnd = globalRegExpSourceMap.end(); + while (itExp != itEnd) { + QRegExp exp = itExp->first; + int index = exp.indexIn(string); + if (index != -1) { + sp->sourcePathMap.insert(string.left(index) + exp.cap(1), itExp->second); + itExp = globalRegExpSourceMap.erase(itExp); + } else { + ++itExp; + } + } + if (globalRegExpSourceMap.isEmpty()) + break; + + const int len = strlen(str); + if (len == 0) + break; + str += len + 1; + } + } + } if (hasEmbeddedInfo || hasLink) return; @@ -1834,10 +1865,12 @@ void DebuggerEngine::checkForReleaseBuild(const DebuggerStartParameters &sp) 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.") - + QLatin1Char('\n') + detailedWarning); + if (warnOnRelease) { + 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.") + + QLatin1Char('\n') + detailedWarning); + } } } // namespace Debugger diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 75f6716bc9a..ce299a09bbb 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -382,7 +382,7 @@ protected: bool isStateDebugging() const; void setStateDebugging(bool on); - static void checkForReleaseBuild(const DebuggerStartParameters& sp); + static void validateExecutable(DebuggerStartParameters *sp); virtual void setupSlaveInferior(); virtual void setupSlaveEngine(); diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index e2175cdb781..34b1ce7277a 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -211,7 +211,13 @@ DebuggerSourcePathMappingWidget::DebuggerSourcePathMappingWidget(QWidget *parent "

This is useful when using a copy of the source tree " "at a location different from the one " "at which the modules where built, for example, while " - "doing remote debugging.")); + "doing remote debugging.

" + "

If source is specified as a regular expression by starting it with an " + "open parenthesis, Qt Creator matches the paths in the ELF with the " + "regular expression to automatically determine the source path.

" + "

Example: (/home/.*/Project)/KnownSubDir -> D:\\Project will " + "substitute ELF built by any user to your local project directory.

" + "")); // Top list/left part. m_treeView->setRootIsDecorated(false); m_treeView->setUniformRowHeights(true);