aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2009-12-15 11:02:09 +0100
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2009-12-15 11:02:09 +0100
commitee3dde9cee445b59e5c41350f2da219e8e2da10b (patch)
treea4b6e6e8345f497fafd819402695a907022e12e4 /src
parent119ea80735314fc416bc32a7503345eda0693e86 (diff)
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: hjk <qtc-committer@nokia.com> Acked-by: mariusSO <qt-info@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/debugger/cdb/cdb.pri1
-rw-r--r--src/plugins/debugger/cdb/cdbbreakpoint.cpp110
-rw-r--r--src/plugins/debugger/cdb/cdbbreakpoint.h3
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine.cpp2
-rw-r--r--src/plugins/debugger/cdb/cdbstacktracecontext.cpp2
5 files changed, 107 insertions, 11 deletions
diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri
index a1ab1d4c4e..6ac5997efa 100644
--- a/src/plugins/debugger/cdb/cdb.pri
+++ b/src/plugins/debugger/cdb/cdb.pri
@@ -62,6 +62,7 @@ SOURCES += \
FORMS += $$PWD/cdboptionspagewidget.ui
+LIBS+=-lpsapi
} else {
message("Debugging Tools for Windows could not be found in $$CDB_PATH")
} # exists($$CDB_PATH)
diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.cpp b/src/plugins/debugger/cdb/cdbbreakpoint.cpp
index 40bec69fae..4393c6a361 100644
--- a/src/plugins/debugger/cdb/cdbbreakpoint.cpp
+++ b/src/plugins/debugger/cdb/cdbbreakpoint.cpp
@@ -37,6 +37,8 @@
#include <QtCore/QDebug>
#include <QtCore/QMap>
+#include <psapi.h>
+
enum { debugBP = 0 };
namespace Debugger {
@@ -215,16 +217,106 @@ bool CDBBreakPoint::add(CIDebugControl* debugControl,
return true;
}
-// Make sure file can be found in editor manager and text markers
-// Use '/' and capitalize drive letter
-QString CDBBreakPoint::canonicalSourceFile(const QString &f)
+// Helper for normalizing file names:
+// Map the device paths in a file name to back to drive letters
+// "/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;
- QString rc = QDir::fromNativeSeparators(f);
- if (rc.size() > 2 && rc.at(1) == QLatin1Char(':'))
- rc[0] = rc.at(0).toUpper();
- return rc;
+ // Get the file size. We need a non-empty file to map it.
+ DWORD dwFileSizeHi = 0;
+ DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
+ 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)
@@ -267,7 +359,7 @@ bool CDBBreakPoint::parseExpression(const QString &expr)
conditionPos = expr.indexOf(sourceFileQuote, colonPos + 1);
if (conditionPos == -1)
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);
bool lineNumberOk = false;
lineNumber = lineNumberS.toInt(&lineNumberOk);
diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.h b/src/plugins/debugger/cdb/cdbbreakpoint.h
index 7b1379617e..3a1e8e09b5 100644
--- a/src/plugins/debugger/cdb/cdbbreakpoint.h
+++ b/src/plugins/debugger/cdb/cdbbreakpoint.h
@@ -80,7 +80,8 @@ struct CDBBreakPoint
QString *errorMessage, QStringList *warnings);
// 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 condition; // condition associated with breakpoint
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index 9f74ec7f9e..ae17ff1ea0 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -625,12 +625,14 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
{
if (debugCDBExecution)
qDebug() << "startDebugger" << *sp;
+ CDBBreakPoint::clearNormalizeFileNameCache();
setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
m_d->checkVersion();
if (m_d->m_hDebuggeeProcess) {
warning(QLatin1String("Internal error: Attempt to start debugger while another process is being debugged."));
setState(AdapterStartFailed, Q_FUNC_INFO, __LINE__);
emit startFailed();
+ return;
}
m_d->clearDisplay();
m_d->m_inferiorStartupComplete = false;
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
index 90329dfe04..e0c4ba0c79 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
@@ -116,7 +116,7 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa
frame.line = ulLine;
// Vitally important to use canonical file that matches editormanager,
// 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);
}