Leaked source code of windows server 2003
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.

576 lines
16 KiB

  1. #include "cplusinc.h"
  2. #include "windows.h"
  3. #include "stdlib.h"
  4. #include "stdio.h"
  5. #include "coredbg.h"
  6. #include <sddl.h>
  7. #define DEBUGBUFLEN 1024
  8. // don't log at all
  9. #define COREDBG_DONT_LOG (COREDBG_DONT_LOG_TO_FILE | COREDBG_DONT_LOG_TO_DEBUGGER)
  10. // if we fail to acquire mutex within this time, shutdown tracing
  11. #define COREDBG_DEBUG_TIMEOUT 10000L
  12. // globals
  13. DWORD g_dwDebugFlags = COREDBG_DEFAULT_FLAGS;
  14. HANDLE g_hDebugFile = INVALID_HANDLE_VALUE;
  15. DWORD g_dwDebugFileSizeLimit = COREDBG_FILE_SIZE_LIMIT;
  16. BOOL g_bDebugInited = FALSE;
  17. static CHAR g_szDebugFileName[MAX_PATH] = { 0 };
  18. static CHAR g_szModuleName[MAX_PATH] = { 0 };
  19. static HANDLE g_hDebugFileMutex = NULL;
  20. static BOOL g_bInited = FALSE;
  21. static BOOL g_bBannerPrinted = FALSE;
  22. #undef TRACE
  23. #ifdef DEBUG
  24. #define TRACE(x) InternalTrace x
  25. #else
  26. #define TRACE(x)
  27. #endif
  28. ////////////////////////////////////////////////
  29. // InternalTrace
  30. //
  31. // Internal tracing for problems in CoreDbgWrite
  32. //
  33. static void InternalTrace(LPCSTR fmt, ...)
  34. {
  35. char buffer[DEBUGBUFLEN];
  36. size_t len = 0;
  37. va_list marker;
  38. va_start(marker, fmt);
  39. _vsnprintf(buffer, DEBUGBUFLEN-3, fmt, marker);
  40. buffer[DEBUGBUFLEN - 3] = 0;
  41. len = strlen(buffer);
  42. if(len > 0)
  43. {
  44. // make sure the line has terminating "\n"
  45. if(buffer[len - 1] != '\n') {
  46. buffer[len++] = '\n';
  47. buffer[len] = '\0';
  48. }
  49. OutputDebugStringA(buffer);
  50. }
  51. va_end(marker);
  52. }
  53. //
  54. // Creates our mutex with appropriate security descriptor
  55. //
  56. BOOL CoreDbgCreateDebugMutex(void)
  57. {
  58. #undef CHECK
  59. #define CHECK(x) if(!(x)) { \
  60. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  61. goto Cleanup; }
  62. #undef CHECK2
  63. #define CHECK2(x, y) if(!(x)) { \
  64. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  65. TRACE(y); goto Cleanup; }
  66. const TCHAR *COREDBG_OBJECT_DACLS= TEXT("D:(A;OICI;GA;;;BA)") // Admin
  67. TEXT( "(A;OICI;GA;;;LS)") // Local Service
  68. TEXT( "(A;OICI;GA;;;AU)"); // Authenticated Users.
  69. SECURITY_ATTRIBUTES SA = {0};
  70. BOOL bSuccess = FALSE;
  71. SA.nLength = sizeof(SECURITY_ATTRIBUTES);
  72. SA.bInheritHandle = FALSE;
  73. SA.lpSecurityDescriptor = NULL;
  74. if (ConvertStringSecurityDescriptorToSecurityDescriptor(
  75. COREDBG_OBJECT_DACLS,
  76. SDDL_REVISION_1,
  77. &(SA.lpSecurityDescriptor),
  78. NULL))
  79. {
  80. CHECK((g_hDebugFileMutex = CreateMutexA(&SA, FALSE, "Global\\WiaDebugFileMut")) != NULL);
  81. bSuccess = TRUE;
  82. }
  83. Cleanup:
  84. if (SA.lpSecurityDescriptor)
  85. {
  86. LocalFree(SA.lpSecurityDescriptor);
  87. }
  88. return bSuccess;
  89. }
  90. ////////////////////////////////////////////////
  91. // CoreDbgWrite
  92. //
  93. // Writes specified number of bytes to a debug
  94. // file, creating it if needed. Thread-safe.
  95. // Registers any failure and from that point returns
  96. // immediately.
  97. //
  98. static void
  99. CoreDbgWrite(LPCSTR buffer, DWORD n)
  100. {
  101. #undef CHECK
  102. #define CHECK(x) if(!(x)) { \
  103. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  104. bCatastrophicFailure = TRUE; goto Cleanup; }
  105. #undef CHECK2
  106. #define CHECK2(x, y) if(!(x)) { \
  107. TRACE(("%s(%d): %s failed (%d)", __FILE__, __LINE__, #x, GetLastError())); \
  108. TRACE(y); bCatastrophicFailure = TRUE; goto Cleanup; }
  109. DWORD cbWritten;
  110. DWORD dwWaitResult;
  111. LARGE_INTEGER newPos = { 0, 0 };
  112. static BOOL bCatastrophicFailure = FALSE;
  113. BOOL bMutexAcquired = FALSE;
  114. // if something is broken, return immediately
  115. if(bCatastrophicFailure) return;
  116. // make sure we have file mutex
  117. if(!g_hDebugFileMutex)
  118. {
  119. CHECK(CoreDbgCreateDebugMutex());
  120. }
  121. // acquire mutex
  122. dwWaitResult = WaitForSingleObject(g_hDebugFileMutex, COREDBG_DEBUG_TIMEOUT);
  123. // if we failed to acquire mutex within the specified timeout,
  124. // shutdown tracing (on free builds users will not know this)
  125. CHECK(dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED);
  126. bMutexAcquired = TRUE;
  127. // make sure we have open file
  128. if(g_hDebugFile == INVALID_HANDLE_VALUE)
  129. {
  130. // attempt to open file
  131. CHECK(ExpandEnvironmentStringsA(COREDBG_FILE_NAME, g_szDebugFileName, MAX_PATH));
  132. g_hDebugFile = CreateFileA(g_szDebugFileName, GENERIC_WRITE,
  133. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  134. CHECK2(g_hDebugFile != INVALID_HANDLE_VALUE,
  135. ("g_szDebugFileName = '%s'", g_szDebugFileName));
  136. }
  137. // seek to the end of file
  138. #ifdef UNICODE
  139. CHECK(SetFilePointerEx(g_hDebugFile, newPos, &newPos, SEEK_END));
  140. #else
  141. CHECK(SetFilePointer(g_hDebugFile, newPos.LowPart, (PLONG)&newPos.LowPart, SEEK_END));
  142. #endif
  143. // check the file size
  144. if(newPos.HighPart != 0 || newPos.LowPart > g_dwDebugFileSizeLimit)
  145. {
  146. static CHAR LogFullMessage[128];
  147. TRACE(("Reached log file maximum size of %d", g_dwDebugFileSizeLimit));
  148. _snprintf(LogFullMessage,
  149. sizeof(LogFullMessage) / sizeof(LogFullMessage[0]) - 1,
  150. "Log file reached maximum size of %d, logging stopped.",
  151. g_dwDebugFileSizeLimit);
  152. LogFullMessage[sizeof(LogFullMessage) / sizeof(LogFullMessage[0]) - 1] = '\0';
  153. CHECK2(WriteFile(g_hDebugFile, LogFullMessage, strlen(LogFullMessage), &cbWritten, NULL), ("%d", cbWritten));
  154. bCatastrophicFailure = TRUE;
  155. }
  156. // write data
  157. CHECK2(WriteFile(g_hDebugFile, buffer, n, &cbWritten, NULL),
  158. ("%d %d", cbWritten, n));
  159. // make sure we write to the disk now.
  160. FlushFileBuffers(g_hDebugFile);
  161. CHECK2(cbWritten == n, ("%d %d", n, cbWritten))
  162. Cleanup:
  163. if(bMutexAcquired) ReleaseMutex(g_hDebugFileMutex);
  164. return;
  165. }
  166. ////////////////////////////////////////////////
  167. // PrintBanner
  168. //
  169. // Since we append to the log file, we need a
  170. // seperator of some sort so we know when a
  171. // new execution has started.
  172. //
  173. void PrintBanner(void)
  174. {
  175. char buffer[1024] = {0};
  176. size_t len = 0;
  177. SYSTEMTIME SysTime;
  178. GetLocalTime(&SysTime);
  179. if (g_dwDebugFlags)
  180. {
  181. _snprintf(buffer,
  182. sizeof(buffer) / sizeof(buffer[0]) - 1,
  183. "====================Start '%s' Debug - Time: %d/%02d/%02d %02d:%02d:%02d:%02d====================\r\n",
  184. g_szModuleName,
  185. SysTime.wYear,
  186. SysTime.wMonth,
  187. SysTime.wDay,
  188. SysTime.wHour,
  189. SysTime.wMinute,
  190. SysTime.wSecond,
  191. SysTime.wMilliseconds);
  192. buffer[sizeof(buffer) / sizeof(buffer[0]) - 1] = '\0';
  193. }
  194. len = strlen(buffer);
  195. if (len > 0)
  196. {
  197. if(!(g_dwDebugFlags & COREDBG_DONT_LOG_TO_FILE))
  198. {
  199. CoreDbgWrite(buffer, len);
  200. }
  201. #ifdef DEBUG
  202. if(!(g_dwDebugFlags & COREDBG_DONT_LOG_TO_DEBUGGER))
  203. {
  204. OutputDebugStringA(buffer);
  205. }
  206. #endif
  207. }
  208. return;
  209. }
  210. ////////////////////////////////////////////////
  211. // CoreDbgGenericTrace
  212. //
  213. // Formats message and writes it into log file
  214. // and/or debugger;
  215. //
  216. void CoreDbgGenericTrace(LPCSTR fmt,
  217. va_list marker,
  218. BOOL bIndent)
  219. {
  220. char buffer[DEBUGBUFLEN];
  221. size_t len = 0;
  222. //
  223. // The first time we ever print a debug statement, lets
  224. // output a seperator line since when we output to file
  225. // we append, this way we can seperate different execution
  226. // sessions.
  227. //
  228. if (!g_bBannerPrinted)
  229. {
  230. PrintBanner();
  231. g_bBannerPrinted = TRUE;
  232. }
  233. if (bIndent)
  234. {
  235. buffer[0] = '\t';
  236. _vsnprintf(&buffer[1], DEBUGBUFLEN - 3, fmt, marker);
  237. }
  238. else
  239. {
  240. _vsnprintf(buffer, DEBUGBUFLEN - 3, fmt, marker);
  241. }
  242. buffer[DEBUGBUFLEN - 3] = 0;
  243. len = strlen(buffer);
  244. if(len > 0)
  245. {
  246. // make sure the line has terminating "\n"
  247. if(buffer[len - 1] != '\n')
  248. {
  249. buffer[len++] = '\r';
  250. buffer[len++] = '\n';
  251. buffer[len] = '\0';
  252. }
  253. if(!(g_dwDebugFlags & COREDBG_DONT_LOG_TO_FILE))
  254. {
  255. CoreDbgWrite(buffer, len);
  256. }
  257. #ifdef DEBUG
  258. if(!(g_dwDebugFlags & COREDBG_DONT_LOG_TO_DEBUGGER))
  259. {
  260. OutputDebugStringA(buffer);
  261. }
  262. #endif
  263. }
  264. }
  265. ////////////////////////////////////////////////
  266. // CoreDbgTrace
  267. //
  268. // Formats message and writes it into log file
  269. // and/or debugger;
  270. //
  271. void CoreDbgTrace(LPCSTR fmt, ...)
  272. {
  273. va_list marker;
  274. // get out if we don't have to log
  275. #ifdef DEBUG
  276. if((g_dwDebugFlags & COREDBG_DONT_LOG) == COREDBG_DONT_LOG)
  277. #else
  278. if(g_dwDebugFlags & COREDBG_DONT_LOG_TO_FILE)
  279. #endif
  280. {
  281. return;
  282. }
  283. va_start(marker, fmt);
  284. CoreDbgGenericTrace(fmt, marker, FALSE);
  285. va_end(marker);
  286. }
  287. ////////////////////////////////////////////////
  288. // CoreDbgTraceWithTab
  289. //
  290. // Formats message and writes it into log file
  291. // and/or debugger;
  292. //
  293. void CoreDbgTraceWithTab(LPCSTR fmt, ...)
  294. {
  295. va_list marker;
  296. // get out if we don't have to log
  297. #ifdef DEBUG
  298. if((g_dwDebugFlags & COREDBG_DONT_LOG) == COREDBG_DONT_LOG)
  299. #else
  300. if(g_dwDebugFlags & COREDBG_DONT_LOG_TO_FILE)
  301. #endif
  302. {
  303. return;
  304. }
  305. va_start(marker, fmt);
  306. CoreDbgGenericTrace(fmt, marker, TRUE);
  307. va_end(marker);
  308. }
  309. ////////////////////////////////////////////////
  310. // GetRegDWORD
  311. //
  312. // Attempts to get a DWORD from the specified
  313. // location. If bSetIfNotExist is set, it
  314. // writes the registry setting to the current
  315. // value in pdwValue.
  316. //
  317. LRESULT GetRegDWORD(HKEY hKey,
  318. const CHAR *pszRegValName,
  319. DWORD *pdwValue,
  320. BOOL bSetIfNotExist)
  321. {
  322. LRESULT lResult = ERROR_SUCCESS;
  323. DWORD dwSize = 0;
  324. DWORD dwType = REG_DWORD;
  325. if ((hKey == NULL) ||
  326. (pszRegValName == NULL) ||
  327. (pdwValue == NULL))
  328. {
  329. return ERROR_INVALID_HANDLE;
  330. }
  331. dwSize = sizeof(DWORD);
  332. lResult = RegQueryValueExA(hKey,
  333. pszRegValName,
  334. NULL,
  335. &dwType,
  336. (BYTE*) pdwValue,
  337. &dwSize);
  338. // if we didn't find the key, create it.
  339. if (bSetIfNotExist)
  340. {
  341. if ((lResult != ERROR_SUCCESS) ||
  342. (dwType != REG_DWORD))
  343. {
  344. lResult = RegSetValueExA(hKey,
  345. pszRegValName,
  346. 0,
  347. REG_DWORD,
  348. (BYTE*) pdwValue,
  349. dwSize);
  350. }
  351. }
  352. return lResult;
  353. }
  354. ////////////////////////////////////////////////
  355. // CoreDbgInit
  356. //
  357. // Overwrite g_dwDebugFlags and g_dwDebugFileSizeLimit
  358. // from registry
  359. //
  360. void CoreDbgInit(HINSTANCE hInstance)
  361. {
  362. HKEY hKey = NULL;
  363. DWORD dwDispositon = 0;
  364. DWORD dwData;
  365. SYSTEMTIME SysTime;
  366. DWORD dwDisposition = 0;
  367. CHAR szModulePath[MAX_PATH + 1] = {0};
  368. CHAR szDebugKey[1023 + 1] = {0};
  369. CHAR *pszFileName = NULL;
  370. GetModuleFileNameA(hInstance, szModulePath, sizeof(szModulePath));
  371. szModulePath[sizeof(szModulePath) - 1] = '\0';
  372. pszFileName = strrchr(szModulePath, '\\');
  373. if (pszFileName == NULL)
  374. {
  375. pszFileName = szModulePath;
  376. }
  377. else
  378. {
  379. pszFileName++;
  380. }
  381. //
  382. // build the registry key.
  383. //
  384. _snprintf(szDebugKey,
  385. sizeof(szDebugKey) / sizeof(szDebugKey[0]) - 1,
  386. "%s\\%s",
  387. COREDBG_FLAGS_REGKEY,
  388. pszFileName);
  389. szDebugKey[sizeof(szDebugKey) / sizeof(szDebugKey[0]) - 1] = '\0';
  390. lstrcpynA(g_szModuleName, pszFileName, sizeof(g_szModuleName));
  391. //
  392. // get/set the debug subkey. The DebugValues value is stored on a per module
  393. // basis
  394. //
  395. if (RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  396. szDebugKey,
  397. 0,
  398. NULL,
  399. 0,
  400. KEY_READ | KEY_WRITE,
  401. NULL,
  402. &hKey,
  403. &dwDisposition) == ERROR_SUCCESS ||
  404. RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  405. szDebugKey,
  406. 0,
  407. NULL,
  408. 0,
  409. KEY_READ,
  410. NULL,
  411. &hKey,
  412. &dwDisposition) == ERROR_SUCCESS)
  413. {
  414. dwData = g_dwDebugFlags;
  415. if (GetRegDWORD(hKey, COREDBG_FLAGS_REGVAL, &dwData, TRUE) == ERROR_SUCCESS)
  416. {
  417. g_dwDebugFlags = dwData;
  418. }
  419. RegCloseKey(hKey);
  420. hKey = NULL;
  421. }
  422. //
  423. // get/set the Max File Size value. This is global to all debug modules since
  424. // the all write to the same file.
  425. //
  426. if (RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  427. COREDBG_FLAGS_REGKEY,
  428. 0,
  429. NULL,
  430. 0,
  431. KEY_READ | KEY_WRITE,
  432. NULL,
  433. &hKey,
  434. &dwDisposition) == ERROR_SUCCESS ||
  435. RegCreateKeyExA(HKEY_LOCAL_MACHINE,
  436. COREDBG_FLAGS_REGKEY,
  437. 0,
  438. NULL,
  439. 0,
  440. KEY_READ,
  441. NULL,
  442. &hKey,
  443. &dwDisposition) == ERROR_SUCCESS)
  444. {
  445. dwData = g_dwDebugFileSizeLimit;
  446. if (GetRegDWORD(hKey, COREDBG_REGVAL_FILE_SIZE_LIMIT, &dwData, TRUE) == ERROR_SUCCESS)
  447. {
  448. g_dwDebugFileSizeLimit = dwData;
  449. }
  450. RegCloseKey(hKey);
  451. hKey = NULL;
  452. }
  453. g_bDebugInited = TRUE;
  454. return;
  455. }
  456. ////////////////////////////////////////////////
  457. // CoreDbgTerm
  458. //
  459. // Clean up resources.
  460. //
  461. void CoreDbgTerm()
  462. {
  463. //
  464. // This is FAR from perfect. The expectation is that
  465. // this function is called in the DllMain of the
  466. // application that is shutting down. Thus, we shouldn't
  467. // really have any synchronization in here. However,
  468. // this then doesn't address the problem of a thread
  469. // calling into CoreDbgWrite above and recreating these
  470. // objects, since we closed them (CoreDbgWrite will re-create
  471. // objects that are closed automatically)
  472. // Even worse, the WaitForSingleObject function's behavior is
  473. // undefined if the handle is closed while it is in a wait
  474. // state.
  475. //
  476. //
  477. if (g_hDebugFile != INVALID_HANDLE_VALUE)
  478. {
  479. CloseHandle(g_hDebugFile);
  480. g_hDebugFile = INVALID_HANDLE_VALUE;
  481. }
  482. if (g_hDebugFileMutex)
  483. {
  484. CloseHandle(g_hDebugFileMutex);
  485. g_hDebugFileMutex = INVALID_HANDLE_VALUE;
  486. }
  487. }