forked from qt-creator/qt-creator
Debugger[CDB]: Add source mapping in stack parser.
This commit is contained in:
@@ -89,6 +89,7 @@ Q_DECLARE_METATYPE(Debugger::Internal::MemoryAgent*)
|
|||||||
|
|
||||||
enum { debug = 0 };
|
enum { debug = 0 };
|
||||||
enum { debugLocals = 0 };
|
enum { debugLocals = 0 };
|
||||||
|
enum { debugSourceMapping = 0 };
|
||||||
enum { debugWatches = 0 };
|
enum { debugWatches = 0 };
|
||||||
enum { debugBreakpoints = 0 };
|
enum { debugBreakpoints = 0 };
|
||||||
|
|
||||||
@@ -462,6 +463,19 @@ void CdbEngine::init()
|
|||||||
m_extensionMessageBuffer.clear();
|
m_extensionMessageBuffer.clear();
|
||||||
m_pendingBreakpointMap.clear();
|
m_pendingBreakpointMap.clear();
|
||||||
m_customSpecialStopData.clear();
|
m_customSpecialStopData.clear();
|
||||||
|
|
||||||
|
// Create local list of mappings in native separators
|
||||||
|
m_sourcePathMappings.clear();
|
||||||
|
const QSharedPointer<GlobalDebuggerOptions> globalOptions = debuggerCore()->globalDebuggerOptions();
|
||||||
|
if (!globalOptions->sourcePathMap.isEmpty()) {
|
||||||
|
typedef GlobalDebuggerOptions::SourcePathMap::const_iterator SourcePathMapIterator;
|
||||||
|
m_sourcePathMappings.reserve(globalOptions->sourcePathMap.size());
|
||||||
|
const SourcePathMapIterator cend = globalOptions->sourcePathMap.constEnd();
|
||||||
|
for (SourcePathMapIterator it = globalOptions->sourcePathMap.constBegin(); it != cend; ++it) {
|
||||||
|
m_sourcePathMappings.push_back(SourcePathMapping(QDir::toNativeSeparators(it.key()),
|
||||||
|
QDir::toNativeSeparators(it.value())));
|
||||||
|
}
|
||||||
|
}
|
||||||
QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process); )
|
QTC_ASSERT(m_process.state() != QProcess::Running, Utils::SynchronousProcess::stopProcess(m_process); )
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2359,24 +2373,46 @@ void CdbEngine::attemptBreakpointSynchronization()
|
|||||||
postCommandSequence(CommandListBreakPoints);
|
postCommandSequence(CommandListBreakPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CdbEngine::normalizeFileName(const QString &f)
|
// Pass a file name through source mapping and normalize upper/lower case (for the editor
|
||||||
|
// manager to correctly process it) and convert to clean path.
|
||||||
|
CdbEngine::NormalizedSourceFileName CdbEngine::sourceMapNormalizeFileNameFromDebugger(const QString &f)
|
||||||
{
|
{
|
||||||
QMap<QString, QString>::const_iterator it = m_normalizedFileCache.constFind(f);
|
// 1) Check cache.
|
||||||
|
QMap<QString, NormalizedSourceFileName>::const_iterator it = m_normalizedFileCache.constFind(f);
|
||||||
if (it != m_normalizedFileCache.constEnd())
|
if (it != m_normalizedFileCache.constEnd())
|
||||||
return it.value();
|
return it.value();
|
||||||
const QString winF = QDir::toNativeSeparators(f);
|
if (debugSourceMapping)
|
||||||
#ifdef Q_OS_WIN
|
qDebug(">sourceMapNormalizeFileNameFromDebugger %s", qPrintable(f));
|
||||||
QString normalized = winNormalizeFileName(winF);
|
// Do we have source path mappings? ->Apply.
|
||||||
#else
|
QString fileName = QDir::toNativeSeparators(f);
|
||||||
QString normalized = winF;
|
if (!m_sourcePathMappings.isEmpty()) {
|
||||||
#endif
|
foreach (const SourcePathMapping &m, m_sourcePathMappings) {
|
||||||
if (normalized.isEmpty()) { // At least upper case drive letter
|
if (fileName.startsWith(m.first, Qt::CaseInsensitive)) {
|
||||||
normalized = winF;
|
fileName.replace(0, m.first.size(), m.second);
|
||||||
if (normalized.size() > 2 && normalized.at(1) == QLatin1Char(':'))
|
break;
|
||||||
normalized[0] = normalized.at(0).toUpper();
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_normalizedFileCache.insert(f, normalized);
|
// Up/lower case normalization according to Windows.
|
||||||
return normalized;
|
#ifdef Q_OS_WIN
|
||||||
|
QString normalized = winNormalizeFileName(fileName);
|
||||||
|
#else
|
||||||
|
QString normalized = fileName;
|
||||||
|
#endif
|
||||||
|
if (debugSourceMapping)
|
||||||
|
qDebug(" sourceMapNormalizeFileNameFromDebugger %s->%s", qPrintable(fileName), qPrintable(normalized));
|
||||||
|
// Check if it really exists, that is normalize worked and QFileInfo confirms it.
|
||||||
|
const bool exists = !normalized.isEmpty() && QFileInfo(normalized).isFile();
|
||||||
|
NormalizedSourceFileName result(QDir::cleanPath(normalized.isEmpty() ? fileName : normalized), exists);
|
||||||
|
if (!exists) {
|
||||||
|
// At least upper case drive letter if failed.
|
||||||
|
if (result.fileName.size() > 2 && result.fileName.at(1) == QLatin1Char(':'))
|
||||||
|
result.fileName[0] = result.fileName.at(0).toUpper();
|
||||||
|
}
|
||||||
|
m_normalizedFileCache.insert(f, result);
|
||||||
|
if (debugSourceMapping)
|
||||||
|
qDebug("<sourceMapNormalizeFileNameFromDebugger %s %d", qPrintable(result.fileName), result.exists);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse frame from GDBMI. Duplicate of the gdb code, but that
|
// Parse frame from GDBMI. Duplicate of the gdb code, but that
|
||||||
@@ -2394,7 +2430,7 @@ static StackFrames parseFrames(const GdbMi &gdbmi)
|
|||||||
if (fullName.isValid()) {
|
if (fullName.isValid()) {
|
||||||
frame.file = QFile::decodeName(fullName.data());
|
frame.file = QFile::decodeName(fullName.data());
|
||||||
frame.line = frameMi.findChild("line").data().toInt();
|
frame.line = frameMi.findChild("line").data().toInt();
|
||||||
frame.usable = QFileInfo(frame.file).isFile();
|
frame.usable = false; // To be decided after source path mapping.
|
||||||
}
|
}
|
||||||
frame.function = QLatin1String(frameMi.findChild("func").data());
|
frame.function = QLatin1String(frameMi.findChild("func").data());
|
||||||
frame.from = QLatin1String(frameMi.findChild("from").data());
|
frame.from = QLatin1String(frameMi.findChild("from").data());
|
||||||
@@ -2422,7 +2458,9 @@ unsigned CdbEngine::parseStackTrace(const GdbMi &data, bool sourceStepInto)
|
|||||||
return ParseStackStepInto;
|
return ParseStackStepInto;
|
||||||
}
|
}
|
||||||
if (hasFile) {
|
if (hasFile) {
|
||||||
frames[i].file = QDir::cleanPath(normalizeFileName(frames.at(i).file));
|
const NormalizedSourceFileName fileName = sourceMapNormalizeFileNameFromDebugger(frames.at(i).file);
|
||||||
|
frames[i].file = fileName.fileName;
|
||||||
|
frames[i].usable = fileName.exists;
|
||||||
if (current == -1 && frames[i].usable)
|
if (current == -1 && frames[i].usable)
|
||||||
current = i;
|
current = i;
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,8 @@
|
|||||||
#include <QtCore/QVariantList>
|
#include <QtCore/QVariantList>
|
||||||
#include <QtCore/QMap>
|
#include <QtCore/QMap>
|
||||||
#include <QtCore/QTime>
|
#include <QtCore/QTime>
|
||||||
|
#include <QtCore/QPair>
|
||||||
|
#include <QtCore/QList>
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
class ConsoleProcess;
|
class ConsoleProcess;
|
||||||
@@ -164,6 +166,14 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
typedef QHash<BreakpointId, BreakpointResponse> PendingBreakPointMap;
|
typedef QHash<BreakpointId, BreakpointResponse> PendingBreakPointMap;
|
||||||
|
typedef QPair<QString, QString> SourcePathMapping;
|
||||||
|
struct NormalizedSourceFileName // Struct for caching mapped/normalized source files.
|
||||||
|
{
|
||||||
|
NormalizedSourceFileName(const QString &fn = QString(), bool e = false) : fileName(fn), exists(e) {}
|
||||||
|
|
||||||
|
QString fileName;
|
||||||
|
bool exists;
|
||||||
|
};
|
||||||
|
|
||||||
enum SpecialStopMode
|
enum SpecialStopMode
|
||||||
{
|
{
|
||||||
@@ -218,8 +228,7 @@ private:
|
|||||||
void handleWidgetAt(const CdbExtensionCommandPtr &);
|
void handleWidgetAt(const CdbExtensionCommandPtr &);
|
||||||
void handleBreakPoints(const CdbExtensionCommandPtr &);
|
void handleBreakPoints(const CdbExtensionCommandPtr &);
|
||||||
void handleBreakPoints(const GdbMi &value);
|
void handleBreakPoints(const GdbMi &value);
|
||||||
|
NormalizedSourceFileName sourceMapNormalizeFileNameFromDebugger(const QString &f);
|
||||||
QString normalizeFileName(const QString &f);
|
|
||||||
void updateLocalVariable(const QByteArray &iname);
|
void updateLocalVariable(const QByteArray &iname);
|
||||||
void updateLocals(bool forNewStackFrame = false);
|
void updateLocals(bool forNewStackFrame = false);
|
||||||
int elapsedLogTime() const;
|
int elapsedLogTime() const;
|
||||||
@@ -243,7 +252,7 @@ private:
|
|||||||
QList<CdbBuiltinCommandPtr> m_builtinCommandQueue;
|
QList<CdbBuiltinCommandPtr> m_builtinCommandQueue;
|
||||||
int m_currentBuiltinCommandIndex; //!< Current command whose output is recorded.
|
int m_currentBuiltinCommandIndex; //!< Current command whose output is recorded.
|
||||||
QList<CdbExtensionCommandPtr> m_extensionCommandQueue;
|
QList<CdbExtensionCommandPtr> m_extensionCommandQueue;
|
||||||
QMap<QString, QString> m_normalizedFileCache;
|
QMap<QString, NormalizedSourceFileName> m_normalizedFileCache;
|
||||||
const QByteArray m_extensionCommandPrefixBA; //!< Library name used as prefix
|
const QByteArray m_extensionCommandPrefixBA; //!< Library name used as prefix
|
||||||
bool m_operateByInstructionPending; //!< Creator operate by instruction action changed.
|
bool m_operateByInstructionPending; //!< Creator operate by instruction action changed.
|
||||||
bool m_operateByInstruction;
|
bool m_operateByInstruction;
|
||||||
@@ -259,6 +268,7 @@ private:
|
|||||||
QHash<QString, QString> m_fileNameModuleHash;
|
QHash<QString, QString> m_fileNameModuleHash;
|
||||||
bool m_ignoreCdbOutput;
|
bool m_ignoreCdbOutput;
|
||||||
QVariantList m_customSpecialStopData;
|
QVariantList m_customSpecialStopData;
|
||||||
|
QList<SourcePathMapping> m_sourcePathMappings;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
Reference in New Issue
Block a user