Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

446 lines
11 KiB

  1. #include "stdafx.h"
  2. // don't log at all
  3. #define COREDBG_DONT_LOG (COREDBG_DONT_LOG_TO_FILE | COREDBG_DONT_LOG_TO_DEBUGGER)
  4. // globals
  5. DWORD g_dwDebugFlags = COREDBG_DEFAULT_FLAGS;
  6. HANDLE g_hDebugFile = INVALID_HANDLE_VALUE;
  7. DWORD g_dwDebugFileSizeLimit = COREDBG_FILE_SIZE_LIMIT;
  8. BOOL g_bDebugInited = FALSE;
  9. static CHAR g_szDebugFileName[MAX_PATH] = { 0 };
  10. static CHAR g_szModuleName[MAX_PATH] = { 0 };
  11. static HANDLE g_hDebugFileMutex = NULL;
  12. static BOOL g_bInited = FALSE;
  13. static BOOL g_bBannerPrinted = FALSE;
  14. #undef TRACE
  15. #ifdef DEBUG
  16. #define TRACE(x) InternalTrace x
  17. #else
  18. #define TRACE(x)
  19. #endif
  20. ////////////////////////////////////////////////
  21. // InternalTrace
  22. //
  23. // Internal tracing for problems in CoreDbgWrite
  24. //
  25. static void InternalTrace(LPCSTR fmt, ...)
  26. {
  27. char buffer[1024];
  28. size_t len = 0;
  29. va_list marker;
  30. va_start(marker, fmt);
  31. _vsnprintf(buffer, 1024, fmt, marker);
  32. len = strlen(buffer);
  33. if(len > 0)
  34. {
  35. // make sure the line has terminating "\n"
  36. if(buffer[len - 1] != '\n') {
  37. buffer[len++] = '\n';
  38. buffer[len] = '\0';
  39. }
  40. OutputDebugStringA(buffer);
  41. }
  42. va_end(marker);
  43. }
  44. ////////////////////////////////////////////////
  45. // CoreDbgWrite
  46. //
  47. // Writes specified number of bytes to a debug
  48. // file, creating it if needed. Thread-safe.
  49. // Registers any failure and from that point returns
  50. // immediately.
  51. //
  52. static void
  53. CoreDbgWrite(LPCSTR buffer, DWORD n)
  54. {
  55. #undef CHECK
  56. #define CHECK(x) if(!(x)) { \
  57. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  58. bCatastrophicFailure = TRUE; goto Cleanup; }
  59. #undef CHECK2
  60. #define CHECK2(x, y) if(!(x)) { \
  61. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  62. TRACE(y); bCatastrophicFailure = TRUE; goto Cleanup; }
  63. DWORD cbWritten;
  64. LARGE_INTEGER newPos = { 0, 0 };
  65. static BOOL bCatastrophicFailure = FALSE;
  66. BOOL bMutexAcquired = FALSE;
  67. // if something is broken, return immediately
  68. if(bCatastrophicFailure) return;
  69. // make sure we have file mutex
  70. if(!g_hDebugFileMutex)
  71. {
  72. CHECK((g_hDebugFileMutex = CreateMutexA(NULL, FALSE, "Global\\WiaDebugFileMut")) != NULL);
  73. }
  74. // acquire mutex
  75. CHECK(WaitForSingleObject(g_hDebugFileMutex, INFINITE) != WAIT_FAILED);
  76. bMutexAcquired = TRUE;
  77. // make sure we have open file
  78. if(g_hDebugFile == INVALID_HANDLE_VALUE)
  79. {
  80. // attempt to open file
  81. CHECK(ExpandEnvironmentStringsA(COREDBG_FILE_NAME, g_szDebugFileName, MAX_PATH));
  82. g_hDebugFile = CreateFileA(g_szDebugFileName, GENERIC_WRITE,
  83. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  84. CHECK2(g_hDebugFile != INVALID_HANDLE_VALUE,
  85. ("g_szDebugFileName = '%s'", g_szDebugFileName));
  86. }
  87. // seek to the end of file
  88. CHECK(SetFilePointerEx(g_hDebugFile, newPos, &newPos, SEEK_END));
  89. // check the file size
  90. if(newPos.HighPart != 0 || newPos.LowPart > g_dwDebugFileSizeLimit)
  91. {
  92. static CHAR LogFullMessage[128];
  93. TRACE(("Reached log file maximum size of %d", g_dwDebugFileSizeLimit));
  94. sprintf(LogFullMessage, "Log file reached maximum size of %d, logging stopped.", g_dwDebugFileSizeLimit);
  95. CHECK2(WriteFile(g_hDebugFile, LogFullMessage, strlen(LogFullMessage), &cbWritten, NULL), ("%d", cbWritten));
  96. bCatastrophicFailure = TRUE;
  97. }
  98. // write data
  99. CHECK2(WriteFile(g_hDebugFile, buffer, n, &cbWritten, NULL),
  100. ("%d %d", cbWritten, n));
  101. // make sure we write to the disk now.
  102. FlushFileBuffers(g_hDebugFile);
  103. CHECK2(cbWritten == n, ("%d %d", n, cbWritten))
  104. Cleanup:
  105. if(bMutexAcquired) ReleaseMutex(g_hDebugFileMutex);
  106. return;
  107. }
  108. ////////////////////////////////////////////////
  109. // PrintBanner
  110. //
  111. // Since we append to the log file, we need a
  112. // seperator of some sort so we know when a
  113. // new execution has started.
  114. //
  115. void PrintBanner(void)
  116. {
  117. char buffer[1024];
  118. size_t len = 0;
  119. SYSTEMTIME SysTime;
  120. GetLocalTime(&SysTime);
  121. if (g_dwDebugFlags)
  122. {
  123. _snprintf(buffer, sizeof(buffer),
  124. "====================Start '%s' Debug - Time: %d/%02d/%02d %02d:%02d:%02d:%02d====================",
  125. g_szModuleName,
  126. SysTime.wYear,
  127. SysTime.wMonth,
  128. SysTime.wDay,
  129. SysTime.wHour,
  130. SysTime.wMinute,
  131. SysTime.wSecond,
  132. SysTime.wMilliseconds);
  133. }
  134. len = strlen(buffer);
  135. if(len > 0)
  136. {
  137. // make sure the line has terminating "\n"
  138. if(buffer[len - 1] != '\n')
  139. {
  140. buffer[len++] = '\r';
  141. buffer[len++] = '\n';
  142. buffer[len] = '\0';
  143. }
  144. if(!(g_dwDebugFlags & COREDBG_DONT_LOG_TO_FILE))
  145. {
  146. CoreDbgWrite(buffer, len);
  147. }
  148. #ifdef DEBUG
  149. if(!(g_dwDebugFlags & COREDBG_DONT_LOG_TO_DEBUGGER))
  150. {
  151. OutputDebugStringA(buffer);
  152. }
  153. #endif
  154. }
  155. return;
  156. }
  157. ////////////////////////////////////////////////
  158. // CoreDbgGenericTrace
  159. //
  160. // Formats message and writes it into log file
  161. // and/or debugger;
  162. //
  163. void CoreDbgGenericTrace(LPCSTR fmt,
  164. va_list marker,
  165. BOOL bIndent)
  166. {
  167. char buffer[1024];
  168. size_t len = 0;
  169. //
  170. // The first time we ever print a debug statement, lets
  171. // output a seperator line since when we output to file
  172. // we append, this way we can seperate different execution
  173. // sessions.
  174. //
  175. if (!g_bBannerPrinted)
  176. {
  177. PrintBanner();
  178. g_bBannerPrinted = TRUE;
  179. }
  180. if (bIndent)
  181. {
  182. buffer[0] = '\t';
  183. _vsnprintf(&buffer[1], 1023, fmt, marker);
  184. }
  185. else
  186. {
  187. _vsnprintf(buffer, 1024, fmt, marker);
  188. }
  189. len = strlen(buffer);
  190. if(len > 0)
  191. {
  192. // make sure the line has terminating "\n"
  193. if(buffer[len - 1] != '\n')
  194. {
  195. buffer[len++] = '\r';
  196. buffer[len++] = '\n';
  197. buffer[len] = '\0';
  198. }
  199. if(!(g_dwDebugFlags & COREDBG_DONT_LOG_TO_FILE))
  200. {
  201. CoreDbgWrite(buffer, len);
  202. }
  203. #ifdef DEBUG
  204. if(!(g_dwDebugFlags & COREDBG_DONT_LOG_TO_DEBUGGER))
  205. {
  206. OutputDebugStringA(buffer);
  207. }
  208. #endif
  209. }
  210. }
  211. ////////////////////////////////////////////////
  212. // CoreDbgTrace
  213. //
  214. // Formats message and writes it into log file
  215. // and/or debugger;
  216. //
  217. void CoreDbgTrace(LPCSTR fmt, ...)
  218. {
  219. va_list marker;
  220. // get out if we don't have to log
  221. #ifdef DEBUG
  222. if((g_dwDebugFlags & COREDBG_DONT_LOG) == COREDBG_DONT_LOG)
  223. #else
  224. if(g_dwDebugFlags & COREDBG_DONT_LOG_TO_FILE)
  225. #endif
  226. {
  227. return;
  228. }
  229. va_start(marker, fmt);
  230. CoreDbgGenericTrace(fmt, marker, FALSE);
  231. va_end(marker);
  232. }
  233. ////////////////////////////////////////////////
  234. // CoreDbgTraceWithTab
  235. //
  236. // Formats message and writes it into log file
  237. // and/or debugger;
  238. //
  239. void CoreDbgTraceWithTab(LPCSTR fmt, ...)
  240. {
  241. va_list marker;
  242. // get out if we don't have to log
  243. #ifdef DEBUG
  244. if((g_dwDebugFlags & COREDBG_DONT_LOG) == COREDBG_DONT_LOG)
  245. #else
  246. if(g_dwDebugFlags & COREDBG_DONT_LOG_TO_FILE)
  247. #endif
  248. {
  249. return;
  250. }
  251. va_start(marker, fmt);
  252. CoreDbgGenericTrace(fmt, marker, TRUE);
  253. va_end(marker);
  254. }
  255. ////////////////////////////////////////////////
  256. // GetRegDWORD
  257. //
  258. // Attempts to get a DWORD from the specified
  259. // location. If bSetIfNotExist is set, it
  260. // writes the registry setting to the current
  261. // value in pdwValue.
  262. //
  263. LRESULT GetRegDWORD(HKEY hKey,
  264. const CHAR *pszRegValName,
  265. DWORD *pdwValue,
  266. BOOL bSetIfNotExist)
  267. {
  268. LRESULT lResult = ERROR_SUCCESS;
  269. DWORD dwSize = 0;
  270. DWORD dwType = REG_DWORD;
  271. if ((hKey == NULL) ||
  272. (pszRegValName == NULL) ||
  273. (pdwValue == NULL))
  274. {
  275. return ERROR_INVALID_HANDLE;
  276. }
  277. dwSize = sizeof(DWORD);
  278. lResult = RegQueryValueExA(hKey,
  279. pszRegValName,
  280. NULL,
  281. &dwType,
  282. (BYTE*) pdwValue,
  283. &dwSize);
  284. // if we didn't find the key, create it.
  285. if (bSetIfNotExist)
  286. {
  287. if ((lResult != ERROR_SUCCESS) ||
  288. (dwType != REG_DWORD))
  289. {
  290. lResult = RegSetValueExA(hKey,
  291. pszRegValName,
  292. 0,
  293. REG_DWORD,
  294. (BYTE*) pdwValue,
  295. dwSize);
  296. }
  297. }
  298. return lResult;
  299. }
  300. ////////////////////////////////////////////////
  301. // CoreDbgInit
  302. //
  303. // Overwrite g_dwDebugFlags and g_dwDebugFileSizeLimit
  304. // from registry
  305. //
  306. void CoreDbgInit(HINSTANCE hInstance)
  307. {
  308. HKEY hKey = NULL;
  309. DWORD dwDispositon = 0;
  310. DWORD dwData;
  311. SYSTEMTIME SysTime;
  312. DWORD dwDisposition = 0;
  313. CHAR szModulePath[MAX_PATH + 1] = {0};
  314. CHAR szDebugKey[1023 + 1] = {0};
  315. CHAR *pszFileName = NULL;
  316. GetModuleFileNameA(hInstance, szModulePath, sizeof(szModulePath));
  317. pszFileName = strrchr(szModulePath, '\\');
  318. if (pszFileName == NULL)
  319. {
  320. pszFileName = szModulePath;
  321. }
  322. else
  323. {
  324. pszFileName++;
  325. }
  326. //
  327. // build the registry key.
  328. //
  329. _snprintf(szDebugKey, sizeof(szDebugKey), "%s\\%s", COREDBG_FLAGS_REGKEY, pszFileName);
  330. lstrcpynA(g_szModuleName, pszFileName, sizeof(g_szModuleName));
  331. //
  332. // get/set the debug subkey. The DebugValues value is stored on a per module
  333. // basis
  334. //
  335. if(RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  336. szDebugKey,
  337. 0,
  338. NULL,
  339. 0,
  340. KEY_READ | KEY_WRITE,
  341. NULL,
  342. &hKey,
  343. &dwDisposition) == ERROR_SUCCESS)
  344. {
  345. dwData = g_dwDebugFlags;
  346. if (GetRegDWORD(hKey, COREDBG_FLAGS_REGVAL, &dwData, TRUE) == ERROR_SUCCESS)
  347. {
  348. g_dwDebugFlags = dwData;
  349. }
  350. RegCloseKey(hKey);
  351. hKey = NULL;
  352. }
  353. //
  354. // get/set the Max File Size value. This is global to all debug modules since
  355. // the all write to the same file.
  356. //
  357. if(RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  358. COREDBG_FLAGS_REGKEY,
  359. 0,
  360. NULL,
  361. 0,
  362. KEY_READ | KEY_WRITE,
  363. NULL,
  364. &hKey,
  365. &dwDisposition) == ERROR_SUCCESS)
  366. {
  367. dwData = g_dwDebugFileSizeLimit;
  368. if (GetRegDWORD(hKey, COREDBG_REGVAL_FILE_SIZE_LIMIT, &dwData, TRUE) == ERROR_SUCCESS)
  369. {
  370. g_dwDebugFileSizeLimit = dwData;
  371. }
  372. RegCloseKey(hKey);
  373. hKey = NULL;
  374. }
  375. g_bDebugInited = TRUE;
  376. return;
  377. }