Commit ee3dde9c authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

CDB: Case-normalize file names returned by CDB



Fixing various problems with breakpoints and opened files caused by CDB
returning lower-case file names.
Task-number: QTCREATORBUG-438
Reviewed-by: default avatarhjk <qtc-committer@nokia.com>
Acked-by: default avatarmariusSO <qt-info@nokia.com>
parent 119ea807
...@@ -62,6 +62,7 @@ SOURCES += \ ...@@ -62,6 +62,7 @@ SOURCES += \
FORMS += $$PWD/cdboptionspagewidget.ui FORMS += $$PWD/cdboptionspagewidget.ui
LIBS+=-lpsapi
} else { } else {
message("Debugging Tools for Windows could not be found in $$CDB_PATH") message("Debugging Tools for Windows could not be found in $$CDB_PATH")
} # exists($$CDB_PATH) } # exists($$CDB_PATH)
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QMap> #include <QtCore/QMap>
#include <psapi.h>
enum { debugBP = 0 }; enum { debugBP = 0 };
namespace Debugger { namespace Debugger {
...@@ -215,16 +217,106 @@ bool CDBBreakPoint::add(CIDebugControl* debugControl, ...@@ -215,16 +217,106 @@ bool CDBBreakPoint::add(CIDebugControl* debugControl,
return true; return true;
} }
// Make sure file can be found in editor manager and text markers // Helper for normalizing file names:
// Use '/' and capitalize drive letter // Map the device paths in a file name to back to drive letters
QString CDBBreakPoint::canonicalSourceFile(const QString &f) // "/Device/HarddiskVolume1/file.cpp" -> "C:/file.cpp"
static bool mapDeviceToDriveLetter(QString *s)
{ {
if (f.isEmpty()) enum { bufSize = 512 };
// Retrieve drive letters and get their device names.
// Do not cache as it may change due to removable/network drives.
TCHAR driveLetters[bufSize];
if (!GetLogicalDriveStrings(bufSize-1, driveLetters))
return false;
TCHAR driveName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
for (const TCHAR *driveLetter = driveLetters; *driveLetter; driveLetter++) {
szDrive[0] = *driveLetter; // Look up each device name
if (QueryDosDevice(szDrive, driveName, MAX_PATH)) {
const QString deviceName = QString::fromUtf16(driveName);
if (s->startsWith(deviceName)) {
s->replace(0, deviceName.size(), QString::fromUtf16(szDrive));
return true;
}
}
}
return false;
}
// Helper for normalizing file names:
// Determine normalized case of a Windows file name (camelcase.cpp -> CamelCase.cpp)
// as the debugger reports lower case file names.
// Restriction: File needs to exists and be non-empty and will be to be opened/mapped.
// This is the MSDN-recommended way of doing that. The result should be cached.
static inline QString normalizeFileNameCaseHelper(const QString &f)
{
HANDLE hFile = CreateFile(f.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
return f; return f;
QString rc = QDir::fromNativeSeparators(f); // Get the file size. We need a non-empty file to map it.
if (rc.size() > 2 && rc.at(1) == QLatin1Char(':')) DWORD dwFileSizeHi = 0;
rc[0] = rc.at(0).toUpper(); DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
return rc; if (dwFileSizeLo == 0 && dwFileSizeHi == 0) {
CloseHandle(hFile);
return f;
}
// Create a file mapping object.
HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
if (!hFileMap) {
CloseHandle(hFile);
return f;
}
// Create a file mapping to get the file name.
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (!pMem) {
CloseHandle(hFileMap);
CloseHandle(hFile);
return f;
}
QString rc;
WCHAR pszFilename[MAX_PATH];
pszFilename[0] = 0;
// Get a file name of the form "/Device/HarddiskVolume1/file.cpp"
if (GetMappedFileName (GetCurrentProcess(), pMem, pszFilename, MAX_PATH)) {
rc = QString::fromUtf16(pszFilename);
if (!mapDeviceToDriveLetter(&rc))
rc.clear();
}
UnmapViewOfFile(pMem);
CloseHandle(hFileMap);
CloseHandle(hFile);
return rc.isEmpty() ? f : rc;
}
// Make sure file can be found in editor manager and text markers
// Use '/', correct case and capitalize drive letter. Use a cache.
typedef QHash<QString, QString> NormalizedFileCache;
Q_GLOBAL_STATIC(NormalizedFileCache, normalizedFileNameCache)
QString CDBBreakPoint::normalizeFileName(const QString &f)
{
QTC_ASSERT(!f.isEmpty(), return f)
const NormalizedFileCache::const_iterator it = normalizedFileNameCache()->constFind(f);
if (it != normalizedFileNameCache()->constEnd())
return it.value();
QString normalizedName = QDir::fromNativeSeparators(normalizeFileNameCaseHelper(f));
// Upcase drive letter for consistency even if case mapping fails.
if (normalizedName.size() > 2 && normalizedName.at(1) == QLatin1Char(':'))
normalizedName[0] = normalizedName.at(0).toUpper();
normalizedFileNameCache()->insert(f, normalizedName);
return f;
}
void CDBBreakPoint::clearNormalizeFileNameCache()
{
normalizedFileNameCache()->clear();
} }
bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage) bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
...@@ -267,7 +359,7 @@ bool CDBBreakPoint::parseExpression(const QString &expr) ...@@ -267,7 +359,7 @@ bool CDBBreakPoint::parseExpression(const QString &expr)
conditionPos = expr.indexOf(sourceFileQuote, colonPos + 1); conditionPos = expr.indexOf(sourceFileQuote, colonPos + 1);
if (conditionPos == -1) if (conditionPos == -1)
return false; return false;
fileName = canonicalSourceFile(expr.mid(1, colonPos - 1)); fileName = normalizeFileName(expr.mid(1, colonPos - 1));
const QString lineNumberS = expr.mid(colonPos + 1, conditionPos - colonPos - 1); const QString lineNumberS = expr.mid(colonPos + 1, conditionPos - colonPos - 1);
bool lineNumberOk = false; bool lineNumberOk = false;
lineNumber = lineNumberS.toInt(&lineNumberOk); lineNumber = lineNumberS.toInt(&lineNumberOk);
......
...@@ -80,7 +80,8 @@ struct CDBBreakPoint ...@@ -80,7 +80,8 @@ struct CDBBreakPoint
QString *errorMessage, QStringList *warnings); QString *errorMessage, QStringList *warnings);
// Return a 'canonical' file (using '/' and capitalized drive letter) // Return a 'canonical' file (using '/' and capitalized drive letter)
static QString canonicalSourceFile(const QString &f); static QString normalizeFileName(const QString &f);
static void clearNormalizeFileNameCache();
QString fileName; // short name of source file QString fileName; // short name of source file
QString condition; // condition associated with breakpoint QString condition; // condition associated with breakpoint
......
...@@ -625,12 +625,14 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> ...@@ -625,12 +625,14 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
{ {
if (debugCDBExecution) if (debugCDBExecution)
qDebug() << "startDebugger" << *sp; qDebug() << "startDebugger" << *sp;
CDBBreakPoint::clearNormalizeFileNameCache();
setState(AdapterStarting, Q_FUNC_INFO, __LINE__); setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
m_d->checkVersion(); m_d->checkVersion();
if (m_d->m_hDebuggeeProcess) { if (m_d->m_hDebuggeeProcess) {
warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged.")); warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__); setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
emit startFailed(); emit startFailed();
return;
} }
m_d->clearDisplay(); m_d->clearDisplay();
m_d->m_inferiorStartupComplete = false; m_d->m_inferiorStartupComplete = false;
......
...@@ -116,7 +116,7 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa ...@@ -116,7 +116,7 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa
frame.line = ulLine; frame.line = ulLine;
// Vitally important to use canonical file that matches editormanager, // Vitally important to use canonical file that matches editormanager,
// else the marker will not show. // else the marker will not show.
frame.file = CDBBreakPoint::canonicalSourceFile(QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf))); frame.file = CDBBreakPoint::normalizeFileName(QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)));
} }
m_frames.push_back(frame); m_frames.push_back(frame);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment