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.

2240 lines
70 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name :
  4. pudebug.c
  5. Abstract:
  6. This module defines functions required for
  7. Debugging and logging messages for a dynamic program.
  8. Author:
  9. Murali R. Krishnan ( MuraliK ) 10-Sept-1994
  10. Modified to be moved to common dll in 22-Dec-1994.
  11. Revisions:
  12. MuraliK 16-May-1995 Code to load and save debug flags from registry
  13. MuraliK 16-Nov-1995 Remove DbgPrint (undoc api)
  14. JasAndre Jan-1998 Replaced tracing mechanism with WMI Tracing
  15. --*/
  16. /************************************************************
  17. * Include Headers
  18. ************************************************************/
  19. # include <nt.h>
  20. # include <ntrtl.h>
  21. # include <nturtl.h>
  22. # include <windows.h>
  23. # include <stdio.h>
  24. # include <stdlib.h>
  25. # include <stdarg.h>
  26. # include <string.h>
  27. # include "pudebug.h"
  28. # include <winbase.h>
  29. # include <coguid.h>
  30. # include <objbase.h>
  31. #ifndef _NO_TRACING_
  32. DEFINE_GUID(IisRtlGuid,
  33. 0x784d8900, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e);
  34. #endif
  35. /*************************************************************
  36. * Global Variables and Default Values
  37. *************************************************************/
  38. # define MAX_PRINTF_OUTPUT ( 10240)
  39. # define DEFAULT_DEBUG_FLAGS_VALUE ( 0)
  40. # define DEBUG_FLAGS_REGISTRY_LOCATION_A "DebugFlags"
  41. # define DEBUG_BREAK_ENABLED_REGKEYNAME_A "BreakOnAssert"
  42. /*************************************************************
  43. * Functions
  44. *************************************************************/
  45. # ifndef _NO_TRACING_
  46. // Critical section used to control access to the list of known guids used for
  47. // WMI tracing
  48. CRITICAL_SECTION g_csGuidList;
  49. // The list of known guids which are used with WMI Tracing
  50. LIST_ENTRY g_pGuidList;
  51. // The sequence number of the trace message we are about to log
  52. LONG g_dwSequenceNumber = 0;
  53. // This flag tells us whether or not to do any WMI handling
  54. BOOL g_bTracingEnabled = FALSE;
  55. // This flag tells us if we had to start WMI tracing
  56. BOOL g_bStartedTracing = FALSE;
  57. TRACEHANDLE g_hLoggerHandle = 0;
  58. // This flag tells us whether to enable the guids as they are defined or to
  59. // wait for an enable command from WMI
  60. BOOL g_bTracingActive = FALSE;
  61. // This flag tells us whether or not to log info to OutputDebugString, this is
  62. // SLOW. It is on by default for CHK builds and off by default for FRE builds
  63. //#ifdef DBG
  64. //BOOL g_ODSEnabled = TRUE;
  65. //#else
  66. BOOL g_ODSEnabled = FALSE;
  67. //#endif
  68. // The filename and session name to use for the WMI Tracing file
  69. char g_szLogFileName[MAX_PATH] = "";
  70. char g_szLogSessionName[MAX_PATH] = "";
  71. // The WMI Tracing buffer size, in KB, and the min and max number of buffers
  72. // that are permitted, and max file size, 0 means use default
  73. // If max file size is set then circular buffers are used
  74. ULONG g_ulBufferSize = 0;
  75. ULONG g_ulMinBuffers = 0;
  76. ULONG g_ulMaxBuffers = 0;
  77. ULONG g_ulMaxFileSize = 0;
  78. // Three special modes that it is possible to start the logger in
  79. BOOL g_bRealTimeMode = FALSE;
  80. BOOL g_bInMemoryMode = FALSE;
  81. BOOL g_bUserMode = FALSE;
  82. // The default values used for control flags and the error level. These
  83. // settings are only used for modules that have their active flags set
  84. DWORD g_dwDefaultControlFlag = 0;
  85. DWORD g_dwDefaultErrorLevel = 0;
  86. // This flag tells us if we have done the registry initialization, we can't
  87. // register with WMI until this has been done
  88. BOOL g_bHaveDoneInit = FALSE;
  89. // This flag tells us whether we have registered with WMI or not
  90. BOOL g_bHadARegister = FALSE;
  91. void SetLevel(int iDefaultErrorLevel, int *piErrorFlags)
  92. /*++
  93. Support function used by all and sundry to convert the level, ie. 1, 2 or 3
  94. into the bitmapped format used in the error flags variable
  95. Arguments:
  96. iDefaultErrorLevel new value to decode for the error level
  97. *piErrorFlags pointer to the variable to set the error level in
  98. Returns:
  99. --*/
  100. {
  101. if (piErrorFlags) {
  102. // Mask out all but the ODS flag
  103. // Note: Why do we do this? There is a problem that if this module is
  104. // compiled as FRE but the caller is CHK then this function would
  105. // erase the callers ODS setting, so by masking out all but the ODS
  106. // flag here we can maintain the callers ODS setting
  107. *piErrorFlags &= DEBUG_FLAG_ODS;
  108. // Then or in the appropriate bit
  109. switch (iDefaultErrorLevel) {
  110. case DEBUG_LEVEL_ERROR:
  111. *piErrorFlags |= DEBUG_FLAG_ERROR;
  112. break;
  113. case DEBUG_LEVEL_WARN:
  114. *piErrorFlags |= DEBUG_FLAG_WARN;
  115. break;
  116. case DEBUG_LEVEL_INFO:
  117. *piErrorFlags |= DEBUG_FLAG_INFO;
  118. break;
  119. default:
  120. break;
  121. };
  122. if (g_ODSEnabled)
  123. *piErrorFlags |= DEBUG_FLAG_ODS;
  124. }
  125. }
  126. SGuidList *FindGuid(
  127. IN GUID *ControlGuid
  128. )
  129. /*++
  130. Support function used by all and sundry to find a guid in the guid list.
  131. NOTE: It is the responsibility of the caller to enter the guid list
  132. critical section before calling this function
  133. Arguments:
  134. *ControlGuid pointer to the guid that we are looking for
  135. Returns:
  136. NULL if the guid is not in the list
  137. *DEBUG_PRINTS the data relating to the guid if it is in the list
  138. --*/
  139. {
  140. LIST_ENTRY *pEntry;
  141. SGuidList *pGE = NULL;
  142. BOOL bFound = FALSE;
  143. for (pEntry = g_pGuidList.Flink;
  144. pEntry != &g_pGuidList;
  145. pEntry = pEntry->Flink)
  146. {
  147. pGE = CONTAINING_RECORD(pEntry,
  148. SGuidList,
  149. m_leEntry);
  150. DBG_ASSERT(TRACESIG == pGE->dwSig);
  151. if (IsEqualGUID(ControlGuid, &pGE->m_dpData.m_guidControl)) {
  152. bFound = TRUE;
  153. break;
  154. }
  155. }
  156. return bFound ? pGE : NULL;
  157. }
  158. dllexp ULONG IISTraceControlCallback(
  159. IN WMIDPREQUESTCODE RequestCode,
  160. IN PVOID RequestContext,
  161. IN OUT ULONG *InOutBufferSize,
  162. IN OUT PVOID Buffer
  163. )
  164. /*++
  165. Callback function supplied to WMI so that it can notify me when the user
  166. requests a change to the level or control flags for logging
  167. Arguments:
  168. RequestCode control code used to determine what function to perform
  169. RequestContext not used
  170. InOutBufferSize size of the buffer supplied by WMI, set to 0 as we don't
  171. send any data back to WMI through this mechanism
  172. Buffer contains EVENT_TRACE_HEADER needed to identify whom a
  173. request is for
  174. Returns:
  175. --*/
  176. {
  177. PEVENT_TRACE_HEADER pHeader = (PEVENT_TRACE_HEADER) Buffer;
  178. TRACEHANDLE hTrace = GetTraceLoggerHandle(Buffer);
  179. LPGUID pGuid = &pHeader->Guid;
  180. ULONG Status = ERROR_SUCCESS;
  181. SGuidList *pGE = NULL;
  182. switch (RequestCode)
  183. {
  184. case WMI_ENABLE_EVENTS:
  185. {
  186. EnterCriticalSection(&g_csGuidList);
  187. DBG_ASSERT(pGuid);
  188. DBG_REQUIRE(pGE = FindGuid(pGuid));
  189. if (pGuid && pGE) {
  190. DEBUG_PRINTS *pGEData = &pGE->m_dpData;
  191. pGEData->m_iControlFlag = GetTraceEnableFlags(hTrace);
  192. pGEData->m_hLogger = hTrace;
  193. if (pGEData->m_piErrorFlags) {
  194. SetLevel(GetTraceEnableLevel(hTrace), pGEData->m_piErrorFlags);
  195. // Flag us as no longer needing an initialize, important step
  196. // to prevent re-initialization attempts in PuInitiateDebug
  197. pGE->m_iInitializeFlags &= ~DEBUG_FLAG_INITIALIZE;
  198. pGE->m_iDefaultErrorLevel = GetTraceEnableLevel(hTrace);
  199. }
  200. else {
  201. pGE->m_iInitializeFlags = DEBUG_FLAG_DEFERRED_START;
  202. pGE->m_iDefaultErrorLevel = GetTraceEnableLevel(hTrace);
  203. }
  204. }
  205. LeaveCriticalSection(&g_csGuidList);
  206. break;
  207. }
  208. case WMI_DISABLE_EVENTS:
  209. {
  210. EnterCriticalSection(&g_csGuidList);
  211. if (pGuid && (NULL != (pGE = FindGuid(pGuid)))) {
  212. DEBUG_PRINTS *pGEData = &pGE->m_dpData;
  213. pGEData->m_iControlFlag = 0;
  214. pGEData->m_hLogger = hTrace;
  215. if (pGEData->m_piErrorFlags) {
  216. SetLevel(0, pGEData->m_piErrorFlags);
  217. pGE->m_iDefaultErrorLevel = 0;
  218. }
  219. }
  220. LeaveCriticalSection(&g_csGuidList);
  221. break;
  222. }
  223. default:
  224. {
  225. char szTemp[MAX_PATH];
  226. _snprintf(szTemp, sizeof(szTemp),
  227. "IISTRACE:\t%s(%d), IISTraceControlCallback: Invalid parameter\n",
  228. __FILE__, __LINE__);
  229. OutputDebugString(szTemp);
  230. Status = ERROR_INVALID_PARAMETER;
  231. break;
  232. }
  233. }
  234. *InOutBufferSize = 0;
  235. return Status;
  236. }
  237. void LoadGuidFromRegistry(char *pszModuleName)
  238. /*++
  239. This function is used to load all the information stored in the registry
  240. about a module and to allocate an entry in the guid list for it
  241. NOTE: It is the responsibility of the caller to enter the guid list
  242. critical section before calling this function
  243. Arguments:
  244. pszModuleName pointer to the name of the module we are about to process
  245. Returns:
  246. --*/
  247. {
  248. char KeyName[MAX_PATH * 2] = REG_TRACE_IIS "\\";
  249. HKEY hk = 0;
  250. // Create the name of the key for this GUID using the english name
  251. strcat(KeyName, pszModuleName);
  252. // Open the GUIDs key
  253. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, KeyName, &hk)) {
  254. WCHAR szwTemp[MAX_PATH];
  255. DWORD dwReadSize;
  256. // 1. Load the guid number from the registry, we can only continue
  257. // processing this module if we find a guid for it
  258. dwReadSize = sizeof(szwTemp);
  259. if (ERROR_SUCCESS == RegQueryValueExW(hk, REG_TRACE_IIS_GUID,
  260. NULL, NULL,
  261. (BYTE *) szwTemp,
  262. &dwReadSize)) {
  263. CLSID ControlGuid;
  264. // 2. Convert the guid string into a guid
  265. if (SUCCEEDED(CLSIDFromString(szwTemp, &ControlGuid))) {
  266. // 3. Ensure it is not already in the guid list
  267. if (!FindGuid(&ControlGuid)) {
  268. DEBUG_PRINTS *pGEData = NULL;
  269. BOOL bGuidEnabled;
  270. int iTemp;
  271. // 4. Try and insert it into the guid list
  272. SGuidList *pGE = (SGuidList *) LocalAlloc(LPTR, sizeof(SGuidList));
  273. if (pGE) {
  274. pGEData = &pGE->m_dpData;
  275. // Set the GuidList signature
  276. pGE->dwSig = TRACESIG;
  277. // Set the SGuidList.m_dpData member variables
  278. strncpy(pGEData->m_rgchLabel,
  279. pszModuleName, MAX_LABEL_LENGTH - 1);
  280. pGEData->m_guidControl = ControlGuid;
  281. pGEData->m_bBreakOnAssert = TRUE; // Default - Break if Assert Fails
  282. // Add it to the head of the list. Put it at the head in case this
  283. // is an object which is being loaded and unloaded continuosly.
  284. InsertHeadList(&g_pGuidList, &pGE->m_leEntry);
  285. // 5. Try to load any previous control settings from the registry
  286. // 5.1 See if the guid is enabled, if so flag us as needing
  287. // to start this guid when we initialize with WMI
  288. dwReadSize = sizeof(bGuidEnabled);
  289. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_ACTIVE,
  290. NULL, NULL,
  291. (BYTE *) &bGuidEnabled,
  292. &dwReadSize)) {
  293. if (bGuidEnabled)
  294. pGE->m_iInitializeFlags = DEBUG_FLAG_INITIALIZE;
  295. }
  296. // Otherwise use the global setting to determine this
  297. else if (g_bTracingActive)
  298. pGE->m_iInitializeFlags = DEBUG_FLAG_INITIALIZE;
  299. // If it is enabled then load the remaining flags
  300. if (pGE->m_iInitializeFlags & DEBUG_FLAG_INITIALIZE) {
  301. // 5.2 So next load the ControlFlags, the flags default
  302. // to the global setting
  303. dwReadSize = sizeof(&iTemp);
  304. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_CONTROL,
  305. NULL, NULL,
  306. (BYTE *) &iTemp,
  307. &dwReadSize))
  308. pGEData->m_iControlFlag = iTemp;
  309. else
  310. pGEData->m_iControlFlag = g_dwDefaultControlFlag;
  311. // 5.3 Then load the Level, it also defaults to the global
  312. // setting
  313. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LEVEL,
  314. NULL, NULL,
  315. (BYTE *) &iTemp,
  316. &dwReadSize)) {
  317. pGE->m_iDefaultErrorLevel = iTemp;
  318. }
  319. else
  320. pGE->m_iDefaultErrorLevel = g_dwDefaultErrorLevel;
  321. }
  322. }
  323. }
  324. }
  325. }
  326. RegCloseKey(hk);
  327. }
  328. }
  329. dllexp void
  330. AddToRegistry(
  331. IN SGuidList *pGE
  332. )
  333. /*++
  334. This function creates new registry entries for this module so that it will
  335. be correctly loaded next time IIS is started
  336. NOTE: It is the responsibility of the caller to enter the guid list
  337. critical section before calling this function
  338. Arguments:
  339. *pGE pointer to the SGuidList entry which has all the
  340. information about the guid to add
  341. Returns:
  342. This returns void as it does not matter to the running program whether
  343. this works or not, it just improves restart performance if it does.
  344. --*/
  345. {
  346. HKEY hk = 0;
  347. HKEY hkNew = 0;
  348. // Open the IIS Trace registry key
  349. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REG_TRACE_IIS, &hk)) {
  350. DEBUG_PRINTS *pGEData = &pGE->m_dpData;
  351. BOOL bCreatedGuid = FALSE;
  352. DWORD dwDisposition;
  353. // 1. Create a new key for the module
  354. if (ERROR_SUCCESS == RegCreateKeyEx(hk, pGEData->m_rgchLabel,
  355. 0, NULL,
  356. REG_OPTION_NON_VOLATILE,
  357. KEY_ALL_ACCESS,
  358. NULL, &hkNew, &dwDisposition))
  359. {
  360. WCHAR szwTemp[MAX_PATH];
  361. // 2. Convert the guid to a string so that we can add it to the
  362. // registry, the format is E.g.
  363. // {37EABAF0-7FB6-11D0-8817-00A0C903B83C}
  364. if (StringFromGUID2(&pGEData->m_guidControl,
  365. (WCHAR *) szwTemp,
  366. MAX_PATH)) {
  367. // 3. Add the guid string to the module information
  368. if (ERROR_SUCCESS == RegSetValueExW(hkNew,
  369. REG_TRACE_IIS_GUID,
  370. 0,
  371. REG_SZ,
  372. (BYTE *) szwTemp,
  373. wcslen(szwTemp) * sizeof(WCHAR))) {
  374. bCreatedGuid = TRUE;
  375. }
  376. }
  377. RegCloseKey(hkNew);
  378. if (!bCreatedGuid && (REG_CREATED_NEW_KEY == dwDisposition)) {
  379. RegDeleteKey(hk, pGEData->m_rgchLabel);
  380. }
  381. }
  382. RegCloseKey(hk);
  383. }
  384. }
  385. TRACEHANDLE
  386. GetTraceFileHandle(
  387. VOID)
  388. /*++
  389. This function create the tracing file for the current log file. It only does
  390. this if a module that has the DEBUG_FLAG_INITIALIZE bit is successfully
  391. registered with WMI.
  392. Arguments:
  393. Returns:
  394. --*/
  395. {
  396. TRACEHANDLE hLogger = 0;
  397. // There must be a valid log file name and session name in order to create
  398. // the trace file
  399. if (g_szLogFileName[0] && g_szLogSessionName[0]) {
  400. struct {
  401. EVENT_TRACE_PROPERTIES Header;
  402. char LoggerName[MAX_PATH];
  403. char LogFileName[MAX_PATH];
  404. } Properties;
  405. PEVENT_TRACE_PROPERTIES LoggerInfo;
  406. PCHAR Offset;
  407. ULONG Status = ERROR_SUCCESS;
  408. LoggerInfo = (PEVENT_TRACE_PROPERTIES)&Properties.Header;
  409. // Set up the request structure
  410. RtlZeroMemory(&Properties, sizeof(Properties));
  411. LoggerInfo->Wnode.BufferSize = sizeof(Properties);
  412. LoggerInfo->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  413. if (0 == g_ulMaxFileSize)
  414. LoggerInfo->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
  415. else {
  416. LoggerInfo->LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
  417. LoggerInfo->MaximumFileSize = g_ulMaxFileSize;
  418. }
  419. if (g_bRealTimeMode)
  420. LoggerInfo->LogFileMode |= EVENT_TRACE_REAL_TIME_MODE;
  421. else if (g_bInMemoryMode)
  422. LoggerInfo->LogFileMode |= EVENT_TRACE_BUFFERING_MODE;
  423. else if (g_bUserMode)
  424. LoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE;
  425. strcpy(&Properties.LoggerName[0], g_szLogSessionName);
  426. strcpy(&Properties.LogFileName[0], g_szLogFileName);
  427. LoggerInfo->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
  428. LoggerInfo->LogFileNameOffset = LoggerInfo->LoggerNameOffset +
  429. MAX_PATH;
  430. LoggerInfo->BufferSize = g_ulBufferSize;
  431. LoggerInfo->MinimumBuffers = g_ulMinBuffers;
  432. LoggerInfo->MaximumBuffers = g_ulMaxBuffers;
  433. Status = QueryTrace(0,
  434. g_szLogSessionName,
  435. (PEVENT_TRACE_PROPERTIES) LoggerInfo);
  436. if (ERROR_SUCCESS == Status)
  437. hLogger = LoggerInfo->Wnode.HistoricalContext;
  438. else if (ERROR_WMI_INSTANCE_NOT_FOUND == Status) {
  439. // The logger is not already started so try to start it now
  440. Status = StartTrace(&hLogger,
  441. g_szLogSessionName,
  442. LoggerInfo);
  443. }
  444. if (ERROR_SUCCESS == Status) {
  445. g_bStartedTracing = TRUE;
  446. strcpy(g_szLogSessionName, &Properties.LoggerName[0]);
  447. strcpy(g_szLogFileName, &Properties.LogFileName[0]);
  448. }
  449. else {
  450. char szTemp[MAX_PATH];
  451. _snprintf(szTemp, sizeof(szTemp),
  452. "IISRTL:\t%s(%d), Unable to get the Logger Handle, return code = %d\n",
  453. __FILE__, __LINE__,
  454. Status);
  455. OutputDebugString(szTemp);
  456. }
  457. }
  458. return hLogger;
  459. }
  460. dllexp VOID
  461. PuUninitiateDebug(
  462. VOID)
  463. /*++
  464. This function stops tracing for the current log file but only if we started
  465. the tracing in the initiate debug
  466. Arguments:
  467. Returns:
  468. --*/
  469. {
  470. BOOL bStartedTracing = FALSE;
  471. DWORD dwError;
  472. EnterCriticalSection(&g_csGuidList);
  473. bStartedTracing = g_bStartedTracing;
  474. g_bStartedTracing = FALSE;
  475. LeaveCriticalSection(&g_csGuidList);
  476. if (bStartedTracing) {
  477. struct {
  478. EVENT_TRACE_PROPERTIES Header;
  479. char LoggerName[MAX_PATH];
  480. char LogFileName[MAX_PATH];
  481. } Properties;
  482. PEVENT_TRACE_PROPERTIES LoggerInfo;
  483. LoggerInfo = (PEVENT_TRACE_PROPERTIES) &Properties.Header;
  484. RtlZeroMemory(&Properties, sizeof(Properties));
  485. LoggerInfo->Wnode.BufferSize = sizeof(Properties);
  486. LoggerInfo->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  487. LoggerInfo->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
  488. LoggerInfo->LogFileNameOffset = LoggerInfo->LoggerNameOffset + MAX_PATH;
  489. // Stop tracing to the log file
  490. dwError = StopTrace(g_hLoggerHandle, g_szLogSessionName, LoggerInfo);
  491. if (dwError == ERROR_SUCCESS) {
  492. strcpy(g_szLogFileName, &Properties.LogFileName[0]);
  493. strcpy(g_szLogSessionName, &Properties.LoggerName[0]);
  494. }
  495. }
  496. }
  497. dllexp VOID
  498. PuInitiateDebug(
  499. VOID
  500. )
  501. /*++
  502. This function iterates through the list of modules in the guid list
  503. registering all of them and starting up logging if that is the state that
  504. was stored in the registry
  505. Arguments:
  506. Returns:
  507. --*/
  508. {
  509. BOOL bStartedLogger = FALSE;
  510. EnterCriticalSection(&g_csGuidList);
  511. if (!g_bHadARegister) {
  512. LIST_ENTRY pRegList;
  513. SGuidList *pGEReg = NULL;
  514. LIST_ENTRY *pEntry;
  515. SGuidList *pGE = NULL;
  516. char szTemp[MAX_PATH];
  517. // Flag us as having done this so that we can later leave this
  518. // critical section
  519. g_bHadARegister = TRUE;
  520. // Only do the WMI registration if tracing is enabled
  521. if (g_bTracingEnabled) {
  522. // Initialize the list of guids which need to be registered with WMI
  523. InitializeListHead(&pRegList);
  524. // Iterate through the guid list
  525. for (pEntry = g_pGuidList.Flink;
  526. pEntry != &g_pGuidList;
  527. pEntry = pEntry->Flink)
  528. {
  529. pGE = CONTAINING_RECORD(pEntry,
  530. SGuidList,
  531. m_leEntry);
  532. DBG_ASSERT(TRACESIG == pGE->dwSig);
  533. // Allocate memory for a local copy of the entry so that we can
  534. // add it to our local list
  535. pGEReg = (SGuidList *) _alloca(sizeof(SGuidList));
  536. if (NULL != pGEReg) {
  537. // Copy the entry and add it to the local list
  538. memcpy(pGEReg, pGE, sizeof(SGuidList));
  539. InsertHeadList(&pRegList, &pGEReg->m_leEntry);
  540. }
  541. }
  542. LeaveCriticalSection(&g_csGuidList);
  543. // Now iterate through our local copy of the list and register all the
  544. // guids with WMI
  545. for (pEntry = pRegList.Flink;
  546. pEntry != &pRegList;
  547. pEntry = pEntry->Flink)
  548. {
  549. TRACE_GUID_REGISTRATION RegGuids;
  550. ULONG Status = ERROR_SUCCESS;
  551. pGEReg = CONTAINING_RECORD(pEntry,
  552. SGuidList,
  553. m_leEntry);
  554. DBG_ASSERT(TRACESIG == pGEReg->dwSig);
  555. // Initialise the GUID registration structure
  556. memset(&RegGuids, 0x00, sizeof(RegGuids));
  557. RegGuids.Guid = (LPGUID) &pGEReg->m_dpData.m_guidControl;
  558. // And then register the guid
  559. Status = RegisterTraceGuidsW(IISTraceControlCallback,
  560. NULL,
  561. (LPGUID) &pGEReg->m_dpData.m_guidControl,
  562. 1,
  563. &RegGuids,
  564. NULL,
  565. NULL,
  566. &pGEReg->m_dpData.m_hRegistration);
  567. if (ERROR_SUCCESS != Status)
  568. {
  569. _snprintf(szTemp, sizeof(szTemp),
  570. "%16s:\t%s(%d), RegisterTraceGuids returned %d, main ID = %08X\n",
  571. pGEReg->m_dpData.m_rgchLabel,
  572. __FILE__, __LINE__,
  573. Status,
  574. pGEReg->m_dpData.m_guidControl.Data1);
  575. OutputDebugString(szTemp);
  576. }
  577. else if (pGEReg->m_iInitializeFlags & DEBUG_FLAG_INITIALIZE) {
  578. // Turn off the initialize flag
  579. pGEReg->m_iInitializeFlags &= ~DEBUG_FLAG_INITIALIZE;
  580. // Get the trace file handle if necessary
  581. if (!bStartedLogger) {
  582. bStartedLogger = TRUE;
  583. g_hLoggerHandle = GetTraceFileHandle();
  584. }
  585. // And enable tracing for the module. If this is successful
  586. // then WMI will call the IISTraceControlCallback
  587. Status = EnableTrace(TRUE,
  588. pGEReg->m_dpData.m_iControlFlag,
  589. pGEReg->m_iDefaultErrorLevel,
  590. (LPGUID) &pGEReg->m_dpData.m_guidControl,
  591. g_hLoggerHandle);
  592. if ((ERROR_SUCCESS != Status) && (ERROR_WMI_ALREADY_ENABLED != Status)) {
  593. _snprintf(szTemp, sizeof(szTemp),
  594. "%16s:\t%s(%d), Unable to EnableTrace, return code = %d\n",
  595. pGEReg->m_dpData.m_rgchLabel,
  596. __FILE__, __LINE__,
  597. Status);
  598. OutputDebugString(szTemp);
  599. }
  600. }
  601. }
  602. // Now re-enter the critical section so that we can save the results
  603. // back to our global data structure
  604. EnterCriticalSection(&g_csGuidList);
  605. for (pEntry = pRegList.Flink;
  606. pEntry != &pRegList;
  607. pEntry = pEntry->Flink)
  608. {
  609. pGEReg = CONTAINING_RECORD(pEntry,
  610. SGuidList,
  611. m_leEntry);
  612. DBG_ASSERT(TRACESIG == pGEReg->dwSig);
  613. // Find the guid in our original guid list
  614. pGE = FindGuid(&pGEReg->m_dpData.m_guidControl);
  615. if (pGE) {
  616. // Save the only two things that could have changed
  617. pGE->m_iInitializeFlags = pGEReg->m_iInitializeFlags;
  618. pGE->m_dpData.m_hRegistration = pGEReg->m_dpData.m_hRegistration;
  619. }
  620. }
  621. }
  622. }
  623. LeaveCriticalSection(&g_csGuidList);
  624. } // PuInitiateDebug()
  625. VOID
  626. PuLoadRegistryInfo(
  627. VOID
  628. )
  629. /*++
  630. This function loads all the registry settings for the project and adds all
  631. the known modules to the Guid list
  632. NOTE: It is the responsibility of the caller to enter the guid list
  633. critical section before calling this function
  634. Arguments:
  635. Returns:
  636. --*/
  637. {
  638. HKEY hk = 0;
  639. // Get the global settings which need only be read once, and only for
  640. // the master
  641. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REG_TRACE_IIS, &hk)) {
  642. DWORD dwIndex = 0;
  643. ULONG ulTemp = 0;
  644. LONG iRegRes = 0;
  645. char szTemp[MAX_PATH];
  646. char szModuleName[MAX_PATH];
  647. DWORD dwReadSize = sizeof(ulTemp);
  648. DWORD dwSizeOfModuleName = sizeof(szModuleName);
  649. // 1. Get the enabled flag, if this is false we do not do any WMI
  650. // processing, by default this is FALSE
  651. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_ENABLED,
  652. NULL, NULL,
  653. (BYTE *) &ulTemp, &dwReadSize))
  654. g_bTracingEnabled = ulTemp;
  655. // 2. Get the AlwaysODS flag, if this is true we will always write
  656. // trace out with OutputDebugString, effectively CHK build
  657. // compatability mode
  658. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_ODS,
  659. NULL, NULL,
  660. (BYTE *) &ulTemp, &dwReadSize))
  661. g_ODSEnabled = ulTemp;
  662. // 3. Determine if the active flag is set, if it was then it means
  663. // that something was active at shut down, so for each module load
  664. // read the appropriate registry entries at start up
  665. dwReadSize = sizeof(ulTemp);
  666. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_ACTIVE,
  667. NULL, NULL,
  668. (BYTE *) &ulTemp, &dwReadSize))
  669. g_bTracingActive = ulTemp;
  670. // 4. Get the trace configuration information, log file name,
  671. // logging session name, min/max number of buffers, buffer size & mode
  672. dwReadSize = sizeof(szTemp);
  673. if (ERROR_SUCCESS == (iRegRes = RegQueryValueEx(hk,
  674. REG_TRACE_IIS_LOG_FILE_NAME,
  675. NULL,
  676. NULL,
  677. (BYTE *) &szTemp,
  678. &dwReadSize)))
  679. strcpy(g_szLogFileName, szTemp);
  680. else if (ERROR_MORE_DATA == iRegRes) {
  681. DBGERROR((DBG_CONTEXT,
  682. "Unable to load tracing logfile name, name too long.\n"));
  683. }
  684. else
  685. DBGWARN((DBG_CONTEXT,
  686. "Unable to load tracing logfile name, Windows error %d\n",
  687. iRegRes));
  688. dwReadSize = sizeof(szTemp);
  689. if (ERROR_SUCCESS == (iRegRes = RegQueryValueEx(hk,
  690. REG_TRACE_IIS_LOG_SESSION_NAME,
  691. NULL,
  692. NULL,
  693. (BYTE *) &szTemp,
  694. &dwReadSize)))
  695. strcpy(g_szLogSessionName, szTemp);
  696. else if (ERROR_MORE_DATA == iRegRes) {
  697. DBGERROR((DBG_CONTEXT,
  698. "Unable to load tracing log session name, name too long.\n"));
  699. }
  700. else
  701. DBGWARN((DBG_CONTEXT,
  702. "Unable to load tracing log session name, Windows error %d\n",
  703. iRegRes));
  704. dwReadSize = sizeof(ulTemp);
  705. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_BUFFER_SIZE,
  706. NULL, NULL,
  707. (BYTE *) &ulTemp, &dwReadSize))
  708. g_ulBufferSize = ulTemp;
  709. dwReadSize = sizeof(ulTemp);
  710. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MIN_BUFFERS,
  711. NULL, NULL,
  712. (BYTE *) &ulTemp, &dwReadSize))
  713. g_ulMinBuffers = ulTemp;
  714. dwReadSize = sizeof(ulTemp);
  715. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_BUFFERS,
  716. NULL, NULL,
  717. (BYTE *) &ulTemp, &dwReadSize))
  718. g_ulMaxBuffers = ulTemp;
  719. dwReadSize = sizeof(ulTemp);
  720. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_FILESIZE,
  721. NULL, NULL,
  722. (BYTE *) &ulTemp, &dwReadSize))
  723. g_ulMaxFileSize = ulTemp;
  724. dwReadSize = sizeof(ulTemp);
  725. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_FILESIZE,
  726. NULL, NULL,
  727. (BYTE *) &ulTemp, &dwReadSize))
  728. g_bRealTimeMode = ulTemp;
  729. dwReadSize = sizeof(ulTemp);
  730. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_FILESIZE,
  731. NULL, NULL,
  732. (BYTE *) &ulTemp, &dwReadSize))
  733. g_bInMemoryMode = ulTemp;
  734. dwReadSize = sizeof(ulTemp);
  735. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LOG_MAX_FILESIZE,
  736. NULL, NULL,
  737. (BYTE *) &ulTemp, &dwReadSize))
  738. g_bUserMode = ulTemp;
  739. // 5. Load the ControlFlags and Level. Both default to 0, off
  740. dwReadSize = sizeof(ulTemp);
  741. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_CONTROL,
  742. NULL, NULL,
  743. (BYTE *) &ulTemp, &dwReadSize))
  744. g_dwDefaultControlFlag = ulTemp;
  745. dwReadSize = sizeof(ulTemp);
  746. if (ERROR_SUCCESS == RegQueryValueEx(hk, REG_TRACE_IIS_LEVEL,
  747. NULL, NULL,
  748. (BYTE *) &ulTemp,
  749. &dwReadSize)) {
  750. g_dwDefaultErrorLevel = ulTemp;
  751. }
  752. DBGPRINTF((DBG_CONTEXT, "Enumerating module for : %s\n", REG_TRACE_IIS));
  753. // Enumerate all the modules listed in the registry for IIS
  754. while (ERROR_NO_MORE_ITEMS != RegEnumKeyEx(hk, dwIndex,
  755. szModuleName,
  756. &dwSizeOfModuleName,
  757. NULL, NULL, NULL, NULL))
  758. {
  759. // Then load the setting for this guid from the registry and
  760. // set up any defaults that are needed
  761. LoadGuidFromRegistry(szModuleName);
  762. dwSizeOfModuleName = sizeof(szModuleName);
  763. ++dwIndex;
  764. }
  765. RegCloseKey(hk);
  766. }
  767. #ifdef DBG
  768. else
  769. if (g_ODSEnabled)
  770. OutputDebugString("IISTRACE: Warning, could not find IIS trace entry in "
  771. "the registry.\n\t Unable to initialize WMI tracing.\n");
  772. #endif
  773. } // PuLoadRegistryInfo()
  774. LPDEBUG_PRINTS
  775. PuCreateDebugPrintsObject(
  776. IN const char * pszPrintLabel,
  777. IN GUID * ControlGuid,
  778. IN int * ErrorFlags,
  779. IN int DefaultControlFlags
  780. )
  781. /*++
  782. This function looks for and if necessary creates a new DEBUG_PRINTS object
  783. for the required module
  784. Arguments:
  785. *pszPrintLabel pointer to null-terminated string containing the
  786. label for program's debugging output
  787. *ControlGuid the unique GUID used to identify this module
  788. *ErrorFlags pointer to the error flags variable used by the
  789. module to determine whether or not to log something
  790. DefaultControlFlags default flags used by IF_DEBUG
  791. Returns:
  792. pointer to a new DEBUG_PRINTS object on success.
  793. Returns NULL on failure.
  794. --*/
  795. {
  796. DEBUG_PRINTS *pGEData = NULL;
  797. LIST_ENTRY *pEntry;
  798. SGuidList *pGE = NULL;
  799. DBG_ASSERT(NULL != ErrorFlags);
  800. DBG_ASSERT(0 != pszPrintLabel[0]);
  801. // Look through the guid list for this module
  802. EnterCriticalSection(&g_csGuidList);
  803. // See if we have done the registry initialization stuff, if we have then
  804. // we should have the guid list. The initialization need only be done once
  805. if (!g_bHaveDoneInit) {
  806. g_bHaveDoneInit = TRUE;
  807. PuLoadRegistryInfo();
  808. }
  809. pGE = FindGuid(ControlGuid);
  810. // If we don't have a pointer to the data member it means we could not
  811. // find the guid, so add it to the list
  812. if (NULL == pGE) {
  813. pGE = (SGuidList *) LocalAlloc(LPTR, sizeof(SGuidList));
  814. if (pGE) {
  815. pGEData = &pGE->m_dpData;
  816. // Set the SGuidList member variables
  817. pGE->dwSig = TRACESIG;
  818. pGE->m_iDefaultErrorLevel = g_dwDefaultErrorLevel;
  819. // Set the SGuidList.m_dpData member variables
  820. strncpy(pGEData->m_rgchLabel,
  821. pszPrintLabel, MAX_LABEL_LENGTH - 1);
  822. pGEData->m_rgchLabel[MAX_LABEL_LENGTH-1] = '\0';
  823. pGEData->m_guidControl = *ControlGuid;
  824. pGEData->m_bBreakOnAssert = TRUE; // Default - Break if Assert Fails
  825. pGEData->m_iControlFlag = g_dwDefaultControlFlag;
  826. // Add it to the head of the list. Put it at the head in case this
  827. // is an object which is being loaded and unloaded continuosly.
  828. InsertHeadList(&g_pGuidList, &pGE->m_leEntry);
  829. // And now update the registry with the information about the guid
  830. // so that we don't have to do this again. While we have already
  831. // done a DBG_ASSERT above we should still verify that the module
  832. // has a name before calling this in case of new components
  833. if (pGEData->m_rgchLabel[0])
  834. AddToRegistry(pGE);
  835. }
  836. }
  837. else
  838. pGEData = &pGE->m_dpData;
  839. // And then if we have the member initialize its data members with the
  840. // parameters supplied by the caller
  841. if (NULL != pGEData) {
  842. DBG_ASSERT(!strncmp(pGEData->m_rgchLabel,
  843. pszPrintLabel,
  844. MAX_LABEL_LENGTH - 1));
  845. // Check to see if we had a deferred start waiting, this would happen
  846. // if we received a WMI initialize during the main phase but we had not
  847. // yet loaded this module
  848. if (pGE->m_iInitializeFlags & DEBUG_FLAG_DEFERRED_START) {
  849. pGE->m_iInitializeFlags &= ~(DEBUG_FLAG_DEFERRED_START | DEBUG_FLAG_INITIALIZE);
  850. }
  851. // Otherwise load the default control flags, but only if we are not
  852. // waiting for initialization. When we are waiting, the registry
  853. // entries we have already loaded are to take precedence
  854. else if (!(pGE->m_iInitializeFlags & DEBUG_FLAG_INITIALIZE)) {
  855. // Set the SGuidList.m_dpData member variables
  856. pGEData->m_iControlFlag = DefaultControlFlags;
  857. }
  858. // Save the pointer to the error flags and set the level
  859. pGEData->m_piErrorFlags = ErrorFlags;
  860. SetLevel(pGE->m_iDefaultErrorLevel, pGEData->m_piErrorFlags);
  861. }
  862. if (NULL == pGEData) {
  863. char szTemp[MAX_PATH];
  864. _snprintf(szTemp, sizeof(szTemp),
  865. "%16s:\t%s(%d), Unable to find in or add a Guid to the trace list, return code = %d\n",
  866. pszPrintLabel, __FILE__, __LINE__,
  867. GetLastError());
  868. OutputDebugString(szTemp);
  869. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  870. }
  871. // And finally ALWAYS or in the ODS flag if enabled
  872. if (g_ODSEnabled && ErrorFlags)
  873. *ErrorFlags |= DEBUG_FLAG_ODS;
  874. LeaveCriticalSection(&g_csGuidList);
  875. return pGEData;
  876. } // PuCreateDebugPrintsObject()
  877. VOID
  878. PuDeleteDebugPrintsObject(
  879. IN OUT LPDEBUG_PRINTS pDebugPrints
  880. )
  881. /*++
  882. This function cleans up the pDebugPrints object and does an frees of
  883. allocated memory that may be required.
  884. Arguments:
  885. pDebugPrints pointer to the DEBUG_PRINTS object.
  886. Returns:
  887. --*/
  888. {
  889. SGuidList *pGE = NULL;
  890. EnterCriticalSection(&g_csGuidList);
  891. if (NULL != pDebugPrints) {
  892. // Since we no longer delete anything or bother to shut it down all we
  893. // need to do here is clear the pointer to the error flag
  894. pDebugPrints->m_piErrorFlags = NULL;
  895. // we allocated an SGuidList that contained the DEBUG_PRINTS struct
  896. pGE = CONTAINING_RECORD(pDebugPrints, SGuidList, m_dpData);
  897. DBG_ASSERT(TRACESIG == pGE->dwSig);
  898. if (pGE)
  899. {
  900. RemoveEntryList(&pGE->m_leEntry);
  901. pGE->dwSig = 0;
  902. LocalFree(pGE);
  903. }
  904. }
  905. LeaveCriticalSection(&g_csGuidList);
  906. } // PuDeleteDebugPrintsObject()
  907. VOID
  908. PuDbgPrintMain(
  909. IN OUT LPDEBUG_PRINTS pDebugPrints,
  910. IN const BOOL bUnicodeRequest,
  911. IN const char * pszFilePath,
  912. IN int nLineNum,
  913. IN const char * pszFormat,
  914. IN va_list argptr
  915. )
  916. /*++
  917. Main function that examines the incoming message and works out what to do
  918. with the header and the message.
  919. Arguments:
  920. pDebugPrints pointer to the DEBUG_PRINTS object.
  921. pszFilePath null terminated string which is the file name
  922. nLineNum the number of the line where the tracing is coming from
  923. pszFormat & ... the format and arguments to be written out
  924. Returns:
  925. --*/
  926. {
  927. LPCSTR pszFileName = strrchr( pszFilePath, '\\');
  928. WCHAR szwOutput[ MAX_PRINTF_OUTPUT + 2];
  929. char *pszOutput = (char *) szwOutput;
  930. char rgchLabel[MAX_LABEL_LENGTH] = "";
  931. TRACEHANDLE hLogger = 0;
  932. TRACE_INFO tiTraceInfo;
  933. DWORD dwSequenceNumber;
  934. BOOL bUseODS = FALSE;
  935. int cchOutput;
  936. int nLength;
  937. // Save the current error state so that we don't disrupt it
  938. DWORD dwErr = GetLastError();
  939. // Skip the '\' and retain only the file name in pszFileName
  940. if (pszFileName)
  941. ++pszFileName;
  942. else
  943. pszFileName = pszFilePath;
  944. EnterCriticalSection(&g_csGuidList);
  945. // Determine if we are to do an OutputDebugString
  946. if (g_ODSEnabled &&
  947. (pDebugPrints &&
  948. pDebugPrints->m_piErrorFlags &&
  949. (*pDebugPrints->m_piErrorFlags & DEBUG_FLAG_ODS)))
  950. {
  951. bUseODS = TRUE;
  952. }
  953. if (NULL != pDebugPrints) {
  954. // Save local copies of the data needed for the ODS case
  955. if (bUseODS) {
  956. strncpy(rgchLabel, pDebugPrints->m_rgchLabel, sizeof(rgchLabel));
  957. }
  958. // Save local copies of the data needed for the WMI Tracing case
  959. if (pDebugPrints->m_hLogger) {
  960. dwSequenceNumber = ++g_dwSequenceNumber;
  961. hLogger = pDebugPrints->m_hLogger;
  962. // Initialize our traceinfo structure
  963. memset(&tiTraceInfo, 0x00, sizeof(tiTraceInfo));
  964. tiTraceInfo.TraceHeader.Guid = pDebugPrints->m_guidControl;
  965. }
  966. }
  967. // All data is now local so we can leave the critical section
  968. LeaveCriticalSection(&g_csGuidList);
  969. if (hLogger) {
  970. int pid = GetCurrentProcessId();
  971. ULONG Status = ERROR_SUCCESS;
  972. // Format the incoming message using vsnprintf() so that we don't exceed
  973. // the buffer length
  974. if (bUnicodeRequest) {
  975. cchOutput = _vsnwprintf(szwOutput, MAX_PRINTF_OUTPUT, (WCHAR *) pszFormat, argptr);
  976. // If the string is too long, we get back a length of -1, so just use the
  977. // partial data that fits in the string
  978. if (cchOutput == -1) {
  979. // Terminate the string properly since _vsnprintf() does not terminate
  980. // properly on failure.
  981. cchOutput = MAX_PRINTF_OUTPUT;
  982. szwOutput[ cchOutput] = '\0';
  983. }
  984. ++cchOutput;
  985. cchOutput *= sizeof(WCHAR);
  986. }
  987. else {
  988. cchOutput = _vsnprintf(pszOutput, sizeof(szwOutput), pszFormat, argptr);
  989. // If the string is too long, we get back a length of -1, so just use the
  990. // partial data that fits in the string
  991. if (cchOutput == -1) {
  992. // Terminate the string properly since _vsnprintf() does not terminate
  993. // properly on failure.
  994. cchOutput = sizeof(szwOutput) - 1;
  995. pszOutput[cchOutput] = '\0';
  996. }
  997. ++cchOutput;
  998. }
  999. // Fill out the Tracing structure
  1000. tiTraceInfo.TraceHeader.Size = sizeof(TRACE_INFO);
  1001. tiTraceInfo.TraceHeader.Class.Type = EVENT_TRACE_TYPE_INFO;
  1002. tiTraceInfo.TraceHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  1003. tiTraceInfo.TraceHeader.ThreadId = GetCurrentThreadId();
  1004. tiTraceInfo.MofFields[0].DataPtr = (ULONGLONG) &dwSequenceNumber;
  1005. tiTraceInfo.MofFields[0].Length = sizeof(int);
  1006. tiTraceInfo.MofFields[1].DataPtr = (ULONGLONG) &pid;
  1007. tiTraceInfo.MofFields[1].Length = sizeof(int);
  1008. tiTraceInfo.MofFields[2].DataPtr = (ULONGLONG) &nLineNum;
  1009. tiTraceInfo.MofFields[2].Length = sizeof(int);
  1010. tiTraceInfo.MofFields[3].DataPtr = (ULONGLONG) pszFileName;
  1011. tiTraceInfo.MofFields[3].Length = strlen(pszFileName) + 1;
  1012. tiTraceInfo.MofFields[4].DataPtr = (ULONGLONG) szwOutput;
  1013. tiTraceInfo.MofFields[4].Length = cchOutput;
  1014. // Send the trace information to the trace class
  1015. TraceEvent(hLogger, (PEVENT_TRACE_HEADER) &tiTraceInfo);
  1016. }
  1017. if (bUseODS) {
  1018. int cchPrologue;
  1019. // Create the prologue
  1020. if (bUnicodeRequest) {
  1021. WCHAR wszLabel[MAX_PRINTF_OUTPUT];
  1022. WCHAR wszFileName[MAX_PRINTF_OUTPUT];
  1023. int iLength = MAX_PRINTF_OUTPUT;
  1024. if (MultiByteToWideChar(CP_ACP, 0, rgchLabel, -1, wszLabel, iLength) &&
  1025. MultiByteToWideChar(CP_ACP, 0, pszFileName, -1, wszFileName, iLength))
  1026. {
  1027. cchOutput = _snwprintf(szwOutput,
  1028. MAX_PRINTF_OUTPUT,
  1029. L"IISTRACE\t%s\t(%lu)\t[ %12s : %5d]\t",
  1030. wszLabel,
  1031. GetCurrentThreadId(),
  1032. wszFileName,
  1033. nLineNum);
  1034. cchOutput = _vsnwprintf(szwOutput + cchOutput,
  1035. MAX_PRINTF_OUTPUT - cchOutput - 1,
  1036. (WCHAR *) pszFormat,
  1037. argptr);
  1038. // If the string is too long, we get back -1. So we get the string
  1039. // length for partial data.
  1040. if (cchOutput == -1) {
  1041. // Terminate the string properly, since _vsnprintf() does not
  1042. // terminate properly on failure.
  1043. cchOutput = MAX_PRINTF_OUTPUT;
  1044. szwOutput[ cchOutput] = '\0';
  1045. }
  1046. OutputDebugStringW(szwOutput);
  1047. }
  1048. }
  1049. else {
  1050. int cchPrologue;
  1051. // Create the prologue
  1052. cchPrologue = _snprintf(pszOutput,
  1053. sizeof(szwOutput),
  1054. "IISTRACE\t%s\t(%lu)\t[ %12s : %5d]\t",
  1055. rgchLabel,
  1056. GetCurrentThreadId(),
  1057. pszFileName,
  1058. nLineNum);
  1059. // Format the incoming message using vsnprintf() so that the overflows are
  1060. // captured
  1061. cchOutput = _vsnprintf(pszOutput + cchPrologue,
  1062. sizeof(szwOutput) - cchPrologue - 1,
  1063. pszFormat,
  1064. argptr);
  1065. // If the string is too long, we get back -1. So we get the string
  1066. // length for partial data.
  1067. if (cchOutput == -1) {
  1068. // Terminate the string properly, since _vsnprintf() does not
  1069. // terminate properly on failure.
  1070. cchOutput = sizeof(szwOutput) - 1;
  1071. pszOutput[cchOutput] = '\0';
  1072. }
  1073. OutputDebugStringA(pszOutput);
  1074. }
  1075. }
  1076. // Restore the error state
  1077. SetLastError( dwErr );
  1078. } // PuDbgPrintMain()
  1079. VOID
  1080. PuDbgPrint(
  1081. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1082. IN const char * pszFilePath,
  1083. IN int nLineNum,
  1084. IN const char * pszFormat,
  1085. ...)
  1086. {
  1087. va_list argsList;
  1088. va_start(argsList, pszFormat);
  1089. PuDbgPrintMain(pDebugPrints, FALSE, pszFilePath, nLineNum, pszFormat, argsList);
  1090. va_end(argsList);
  1091. }
  1092. dllexp VOID
  1093. PuDbgPrintW(
  1094. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1095. IN const char * pszFilePath,
  1096. IN int nLineNum,
  1097. IN const WCHAR * pszFormat,
  1098. ...)
  1099. {
  1100. va_list argsList;
  1101. va_start(argsList, pszFormat);
  1102. PuDbgPrintMain(pDebugPrints, TRUE, pszFilePath, nLineNum, (char *) pszFormat, argsList);
  1103. va_end(argsList);
  1104. }
  1105. VOID
  1106. PuDbgDumpMain(
  1107. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1108. IN BOOL bUnicodeRequest,
  1109. IN const char * pszFilePath,
  1110. IN int nLineNum,
  1111. IN const char * pszDump
  1112. )
  1113. /*++
  1114. Function that write a dump of a buffer out to the trace file.
  1115. Arguments:
  1116. pDebugPrints pointer to the DEBUG_PRINTS object.
  1117. pszFilePath null terminated string which is the file name
  1118. nLineNum the number of the line where the tracing is coming from
  1119. pszDump the dump to be written out
  1120. Returns:
  1121. --*/
  1122. {
  1123. LPCSTR pszFileName = strrchr( pszFilePath, '\\');
  1124. TRACEHANDLE hLogger = 0;
  1125. TRACE_INFO tiTraceInfo;
  1126. DWORD dwSequenceNumber;
  1127. BOOL bUseODS = FALSE;
  1128. DWORD cbDump;
  1129. // Save the current error state so that we don't disrupt it
  1130. DWORD dwErr = GetLastError();
  1131. // Skip the complete path name and retain only the file name in pszFileName
  1132. if ( pszFileName)
  1133. ++pszFileName;
  1134. else
  1135. pszFileName = pszFilePath;
  1136. EnterCriticalSection(&g_csGuidList);
  1137. // Determine if we are to do an OutputDebugString
  1138. if (g_ODSEnabled ||
  1139. (pDebugPrints &&
  1140. pDebugPrints->m_piErrorFlags &&
  1141. (*pDebugPrints->m_piErrorFlags & DEBUG_FLAG_ODS)))
  1142. {
  1143. bUseODS = TRUE;
  1144. }
  1145. // Save local copies of the data needed for the WMI Tracing case
  1146. if ((NULL != pDebugPrints) && pDebugPrints->m_hLogger) {
  1147. dwSequenceNumber = ++g_dwSequenceNumber;
  1148. hLogger = pDebugPrints->m_hLogger;
  1149. if (bUnicodeRequest)
  1150. cbDump = (wcslen((WCHAR *) pszDump) + 1) * sizeof(WCHAR);
  1151. else
  1152. cbDump = strlen( pszDump) + 1;
  1153. // Initialize our traceinfo structure
  1154. memset(&tiTraceInfo, 0x00, sizeof(tiTraceInfo));
  1155. tiTraceInfo.TraceHeader.Guid = pDebugPrints->m_guidControl;
  1156. }
  1157. // All data is now local so we can leave the critical section
  1158. LeaveCriticalSection(&g_csGuidList);
  1159. // Send the outputs to respective files.
  1160. if (hLogger) {
  1161. int pid = GetCurrentProcessId();
  1162. // Fill out the Tracing structure
  1163. tiTraceInfo.TraceHeader.Size = sizeof(TRACE_INFO);
  1164. tiTraceInfo.TraceHeader.Class.Type = EVENT_TRACE_TYPE_INFO;
  1165. tiTraceInfo.TraceHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  1166. tiTraceInfo.TraceHeader.ThreadId = GetCurrentThreadId();
  1167. tiTraceInfo.MofFields[0].DataPtr = (ULONGLONG) &dwSequenceNumber;
  1168. tiTraceInfo.MofFields[0].Length = sizeof(int);
  1169. tiTraceInfo.MofFields[1].DataPtr = (ULONGLONG) &pid;
  1170. tiTraceInfo.MofFields[1].Length = sizeof(int);
  1171. tiTraceInfo.MofFields[2].DataPtr = (ULONGLONG) &nLineNum;
  1172. tiTraceInfo.MofFields[2].Length = sizeof(int);
  1173. tiTraceInfo.MofFields[3].DataPtr = (ULONGLONG) pszFileName;
  1174. tiTraceInfo.MofFields[3].Length = strlen(pszFileName) + 1;
  1175. tiTraceInfo.MofFields[4].DataPtr = (ULONGLONG) pszDump;
  1176. tiTraceInfo.MofFields[4].Length = cbDump;
  1177. // Send the trace information to the trace class
  1178. TraceEvent(hLogger, (PEVENT_TRACE_HEADER) &tiTraceInfo);
  1179. }
  1180. if (bUseODS) {
  1181. if (bUnicodeRequest)
  1182. OutputDebugStringW((WCHAR *) pszDump);
  1183. else
  1184. OutputDebugString(pszDump);
  1185. }
  1186. // Restore the error state
  1187. SetLastError( dwErr );
  1188. } // PuDbgDumpMain()
  1189. VOID
  1190. PuDbgDump(
  1191. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1192. IN const char * pszFilePath,
  1193. IN int nLineNum,
  1194. IN const char * pszDump
  1195. )
  1196. {
  1197. PuDbgDumpMain(pDebugPrints, FALSE, pszFilePath, nLineNum, pszDump);
  1198. }
  1199. dllexp VOID
  1200. PuDbgDumpW(
  1201. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1202. IN const char * pszFilePath,
  1203. IN int nLineNum,
  1204. IN const WCHAR * pszDump
  1205. )
  1206. {
  1207. PuDbgDumpMain(pDebugPrints, TRUE, pszFilePath, nLineNum, (char *) pszDump);
  1208. }
  1209. //
  1210. // N.B. For PuDbgCaptureContext() to work properly, the calling function
  1211. // *must* be __cdecl, and must have a "normal" stack frame. So, we decorate
  1212. // PuDbgAssertFailed() with the __cdecl modifier and disable the frame pointer
  1213. // omission (FPO) optimization.
  1214. //
  1215. #pragma optimize( "y", off ) // disable frame pointer omission (FPO)
  1216. VOID
  1217. __cdecl
  1218. PuDbgAssertFailed(
  1219. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1220. IN const char * pszFilePath,
  1221. IN int nLineNum,
  1222. IN const char * pszExpression)
  1223. /*++
  1224. This function calls assertion failure and records assertion failure
  1225. in log file.
  1226. --*/
  1227. {
  1228. CONTEXT context;
  1229. PuDbgCaptureContext( &context );
  1230. PuDbgPrint(pDebugPrints, pszFilePath, nLineNum,
  1231. " Assertion (%s) Failed\n"
  1232. " use !cxr %p to dump context\n",
  1233. pszExpression,
  1234. &context);
  1235. if (( NULL == pDebugPrints) || (TRUE == pDebugPrints->m_bBreakOnAssert))
  1236. {
  1237. DebugBreak();
  1238. }
  1239. } // PuDbgAssertFailed()
  1240. #pragma optimize( "", on ) // restore frame pointer omission (FPO)
  1241. # else // !_NO_TRACING_
  1242. LPDEBUG_PRINTS
  1243. PuCreateDebugPrintsObject(
  1244. IN const char * pszPrintLabel,
  1245. IN DWORD dwOutputFlags)
  1246. /*++
  1247. This function creates a new DEBUG_PRINTS object for the required
  1248. program.
  1249. Arguments:
  1250. pszPrintLabel pointer to null-terminated string containing
  1251. the label for program's debugging output
  1252. dwOutputFlags DWORD containing the output flags to be used.
  1253. Returns:
  1254. pointer to a new DEBUG_PRINTS object on success.
  1255. Returns NULL on failure.
  1256. --*/
  1257. {
  1258. LPDEBUG_PRINTS pDebugPrints;
  1259. pDebugPrints = GlobalAlloc( GPTR, sizeof( DEBUG_PRINTS));
  1260. if ( pDebugPrints != NULL) {
  1261. if ( strlen( pszPrintLabel) < MAX_LABEL_LENGTH) {
  1262. strcpy( pDebugPrints->m_rgchLabel, pszPrintLabel);
  1263. } else {
  1264. strncpy( pDebugPrints->m_rgchLabel,
  1265. pszPrintLabel, MAX_LABEL_LENGTH - 1);
  1266. pDebugPrints->m_rgchLabel[MAX_LABEL_LENGTH-1] = '\0';
  1267. // terminate string
  1268. }
  1269. memset( pDebugPrints->m_rgchLogFilePath, 0, MAX_PATH);
  1270. memset( pDebugPrints->m_rgchLogFileName, 0, MAX_PATH);
  1271. pDebugPrints->m_LogFileHandle = INVALID_HANDLE_VALUE;
  1272. pDebugPrints->m_dwOutputFlags = dwOutputFlags;
  1273. pDebugPrints->m_StdErrHandle = GetStdHandle( STD_ERROR_HANDLE);
  1274. pDebugPrints->m_fInitialized = TRUE;
  1275. pDebugPrints->m_fBreakOnAssert= TRUE; // Default - Break if Assert Fails
  1276. }
  1277. return ( pDebugPrints);
  1278. } // PuCreateDebugPrintsObject()
  1279. LPDEBUG_PRINTS
  1280. PuDeleteDebugPrintsObject(
  1281. IN OUT LPDEBUG_PRINTS pDebugPrints)
  1282. /*++
  1283. This function cleans up the pDebugPrints object and
  1284. frees the allocated memory.
  1285. Arguments:
  1286. pDebugPrints poitner to the DEBUG_PRINTS object.
  1287. Returns:
  1288. NULL on success.
  1289. pDebugPrints() if the deallocation failed.
  1290. --*/
  1291. {
  1292. if ( pDebugPrints != NULL) {
  1293. DWORD dwError = PuCloseDbgPrintFile( pDebugPrints);
  1294. if ( dwError != NO_ERROR) {
  1295. SetLastError( dwError);
  1296. } else {
  1297. pDebugPrints = GlobalFree( pDebugPrints); // returns NULL on success
  1298. }
  1299. }
  1300. return ( pDebugPrints);
  1301. } // PuDeleteDebugPrintsObject()
  1302. dllexp VOID
  1303. PuSetDbgOutputFlags(
  1304. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1305. IN DWORD dwFlags)
  1306. {
  1307. if ( pDebugPrints == NULL) {
  1308. SetLastError( ERROR_INVALID_PARAMETER);
  1309. } else {
  1310. pDebugPrints->m_dwOutputFlags = dwFlags;
  1311. }
  1312. return;
  1313. } // PuSetDbgOutputFlags()
  1314. dllexp DWORD
  1315. PuGetDbgOutputFlags(
  1316. IN const LPDEBUG_PRINTS pDebugPrints)
  1317. {
  1318. return ( pDebugPrints != NULL) ? pDebugPrints->m_dwOutputFlags : 0;
  1319. } // PuGetDbgOutputFlags()
  1320. DWORD
  1321. PuOpenDbgFileLocal(
  1322. IN OUT LPDEBUG_PRINTS pDebugPrints)
  1323. {
  1324. if ( pDebugPrints == NULL)
  1325. return ERROR_INVALID_PARAMETER;
  1326. if ( pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) {
  1327. //
  1328. // Silently return as a file handle exists.
  1329. //
  1330. return ( NO_ERROR);
  1331. }
  1332. pDebugPrints->m_LogFileHandle =
  1333. CreateFile( pDebugPrints->m_rgchLogFileName,
  1334. GENERIC_WRITE,
  1335. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1336. NULL,
  1337. OPEN_ALWAYS,
  1338. FILE_ATTRIBUTE_NORMAL,
  1339. NULL);
  1340. if ( pDebugPrints->m_LogFileHandle == INVALID_HANDLE_VALUE) {
  1341. CHAR pchBuffer[1024];
  1342. DWORD dwError = GetLastError();
  1343. wsprintfA( pchBuffer,
  1344. " Critical Error: Unable to Open File %s. Error = %d\n",
  1345. pDebugPrints->m_rgchLogFileName, dwError);
  1346. OutputDebugString( pchBuffer);
  1347. return ( dwError);
  1348. }
  1349. return ( NO_ERROR);
  1350. } // PuOpenDbgFileLocal()
  1351. dllexp DWORD
  1352. PuOpenDbgPrintFile(
  1353. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1354. IN const char * pszFileName,
  1355. IN const char * pszPathForFile)
  1356. /*++
  1357. Opens a Debugging log file. This function can be called to set path
  1358. and name of the debugging file.
  1359. Arguments:
  1360. pszFileName pointer to null-terminated string containing
  1361. the name of the file.
  1362. pszPathForFile pointer to null-terminated string containing the
  1363. path for the given file.
  1364. If NULL, then the old place where dbg files were
  1365. stored is used or if none,
  1366. default windows directory will be used.
  1367. Returns:
  1368. Win32 error codes. NO_ERROR on success.
  1369. --*/
  1370. {
  1371. if ( pszFileName == NULL || pDebugPrints == NULL) {
  1372. return ( ERROR_INVALID_PARAMETER);
  1373. }
  1374. //
  1375. // Setup the Path information. if necessary.
  1376. //
  1377. if ( pszPathForFile != NULL) {
  1378. // Path is being changed.
  1379. if ( strlen( pszPathForFile) < MAX_PATH) {
  1380. strcpy( pDebugPrints->m_rgchLogFilePath, pszPathForFile);
  1381. } else {
  1382. return ( ERROR_INVALID_PARAMETER);
  1383. }
  1384. } else {
  1385. if ( pDebugPrints->m_rgchLogFilePath[0] == '\0' && // no old path
  1386. !GetWindowsDirectory( pDebugPrints->m_rgchLogFilePath, MAX_PATH)) {
  1387. //
  1388. // Unable to get the windows default directory. Use current dir
  1389. //
  1390. strcpy( pDebugPrints->m_rgchLogFilePath, ".");
  1391. }
  1392. }
  1393. //
  1394. // Should need be, we need to create this directory for storing file
  1395. //
  1396. //
  1397. // Form the complete Log File name and open the file.
  1398. //
  1399. if ( (strlen( pszFileName) + strlen( pDebugPrints->m_rgchLogFilePath))
  1400. >= MAX_PATH) {
  1401. return ( ERROR_NOT_ENOUGH_MEMORY);
  1402. }
  1403. // form the complete path
  1404. strcpy( pDebugPrints->m_rgchLogFileName, pDebugPrints->m_rgchLogFilePath);
  1405. if ( pDebugPrints->m_rgchLogFileName[ strlen(pDebugPrints->m_rgchLogFileName) - 1]
  1406. != '\\') {
  1407. // Append a \ if necessary
  1408. strcat( pDebugPrints->m_rgchLogFileName, "\\");
  1409. };
  1410. strcat( pDebugPrints->m_rgchLogFileName, pszFileName);
  1411. return PuOpenDbgFileLocal( pDebugPrints);
  1412. } // PuOpenDbgPrintFile()
  1413. dllexp DWORD
  1414. PuReOpenDbgPrintFile(
  1415. IN OUT LPDEBUG_PRINTS pDebugPrints)
  1416. /*++
  1417. This function closes any open log file and reopens a new copy.
  1418. If necessary. It makes a backup copy of the file.
  1419. --*/
  1420. {
  1421. if ( pDebugPrints == NULL) {
  1422. return ( ERROR_INVALID_PARAMETER);
  1423. }
  1424. PuCloseDbgPrintFile( pDebugPrints); // close any existing file.
  1425. if ( pDebugPrints->m_dwOutputFlags & DbgOutputBackup) {
  1426. // MakeBkupCopy();
  1427. OutputDebugString( " Error: MakeBkupCopy() Not Yet Implemented\n");
  1428. }
  1429. return PuOpenDbgFileLocal( pDebugPrints);
  1430. } // PuReOpenDbgPrintFile()
  1431. dllexp DWORD
  1432. PuCloseDbgPrintFile(
  1433. IN OUT LPDEBUG_PRINTS pDebugPrints)
  1434. {
  1435. DWORD dwError = NO_ERROR;
  1436. if ( pDebugPrints == NULL ) {
  1437. dwError = ERROR_INVALID_PARAMETER;
  1438. } else {
  1439. if ( pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) {
  1440. FlushFileBuffers( pDebugPrints->m_LogFileHandle);
  1441. if ( !CloseHandle( pDebugPrints->m_LogFileHandle)) {
  1442. CHAR pchBuffer[1024];
  1443. dwError = GetLastError();
  1444. wsprintf( pchBuffer,
  1445. "CloseDbgPrintFile() : CloseHandle( %d) failed."
  1446. " Error = %d\n",
  1447. pDebugPrints->m_LogFileHandle,
  1448. dwError);
  1449. OutputDebugString( pchBuffer);
  1450. }
  1451. pDebugPrints->m_LogFileHandle = INVALID_HANDLE_VALUE;
  1452. }
  1453. }
  1454. return ( dwError);
  1455. } // DEBUG_PRINTS::CloseDbgPrintFile()
  1456. VOID
  1457. PuDbgPrint(
  1458. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1459. IN const char * pszFilePath,
  1460. IN int nLineNum,
  1461. IN const char * pszFormat,
  1462. ...)
  1463. /*++
  1464. Main function that examines the incoming message and prints out a header
  1465. and the message.
  1466. --*/
  1467. {
  1468. LPCSTR pszFileName = strrchr( pszFilePath, '\\');
  1469. char pszOutput[ MAX_PRINTF_OUTPUT + 2];
  1470. LPCSTR pszMsg = "";
  1471. INT cchOutput;
  1472. INT cchPrologue;
  1473. va_list argsList;
  1474. DWORD dwErr;
  1475. //
  1476. // Skip the complete path name and retain file name in pszName
  1477. //
  1478. if ( pszFileName== NULL) {
  1479. pszFileName = pszFilePath; // if skipping \\ yields nothing use whole path.
  1480. }
  1481. # ifdef _PRINT_REASONS_INCLUDED_
  1482. switch (pr) {
  1483. case PrintError:
  1484. pszMsg = "ERROR: ";
  1485. break;
  1486. case PrintWarning:
  1487. pszMsg = "WARNING: ";
  1488. break;
  1489. case PrintCritical:
  1490. pszMsg = "FATAL ERROR ";
  1491. break;
  1492. case PrintAssertion:
  1493. pszMsg = "ASSERTION Failed ";
  1494. break;
  1495. case PrintLog:
  1496. pfnPrintFunction = &DEBUG_PRINTS::DebugPrintNone;
  1497. default:
  1498. break;
  1499. } /* switch */
  1500. # endif // _PRINT_REASONS_INClUDED_
  1501. dwErr = GetLastError();
  1502. // Format the message header
  1503. cchPrologue = wsprintf( pszOutput, "IISTRACE\t%s\t(%lu)\t[ %12s : %05d]\t",
  1504. pDebugPrints ? pDebugPrints->m_rgchLabel : "??",
  1505. GetCurrentThreadId(),
  1506. pszFileName, nLineNum);
  1507. // Format the incoming message using vsnprintf() so that the overflows are
  1508. // captured
  1509. va_start( argsList, pszFormat);
  1510. cchOutput = _vsnprintf( pszOutput + cchPrologue,
  1511. MAX_PRINTF_OUTPUT - cchPrologue - 1,
  1512. pszFormat, argsList);
  1513. va_end( argsList);
  1514. //
  1515. // The string length is long, we get back -1.
  1516. // so we get the string length for partial data.
  1517. //
  1518. if ( cchOutput == -1 ) {
  1519. //
  1520. // terminate the string properly,
  1521. // since _vsnprintf() does not terminate properly on failure.
  1522. //
  1523. cchOutput = MAX_PRINTF_OUTPUT;
  1524. pszOutput[ cchOutput] = '\0';
  1525. }
  1526. //
  1527. // Send the outputs to respective files.
  1528. //
  1529. if ( pDebugPrints != NULL)
  1530. {
  1531. if ( pDebugPrints->m_dwOutputFlags & DbgOutputStderr) {
  1532. DWORD nBytesWritten;
  1533. ( VOID) WriteFile( pDebugPrints->m_StdErrHandle,
  1534. pszOutput,
  1535. strlen( pszOutput),
  1536. &nBytesWritten,
  1537. NULL);
  1538. }
  1539. if ( pDebugPrints->m_dwOutputFlags & DbgOutputLogFile &&
  1540. pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) {
  1541. DWORD nBytesWritten;
  1542. //
  1543. // Truncation of log files. Not yet implemented.
  1544. ( VOID) WriteFile( pDebugPrints->m_LogFileHandle,
  1545. pszOutput,
  1546. strlen( pszOutput),
  1547. &nBytesWritten,
  1548. NULL);
  1549. }
  1550. }
  1551. if ( pDebugPrints == NULL ||
  1552. pDebugPrints->m_dwOutputFlags & DbgOutputKdb)
  1553. {
  1554. OutputDebugString( pszOutput);
  1555. }
  1556. SetLastError( dwErr );
  1557. return;
  1558. } // PuDbgPrint()
  1559. VOID
  1560. PuDbgDump(
  1561. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1562. IN const char * pszFilePath,
  1563. IN int nLineNum,
  1564. IN const char * pszDump
  1565. )
  1566. {
  1567. LPCSTR pszFileName = strrchr( pszFilePath, '\\');
  1568. LPCSTR pszMsg = "";
  1569. DWORD dwErr;
  1570. DWORD cbDump;
  1571. //
  1572. // Skip the complete path name and retain file name in pszName
  1573. //
  1574. if ( pszFileName== NULL) {
  1575. pszFileName = pszFilePath;
  1576. }
  1577. dwErr = GetLastError();
  1578. // No message header for this dump
  1579. cbDump = strlen( pszDump);
  1580. //
  1581. // Send the outputs to respective files.
  1582. //
  1583. if ( pDebugPrints != NULL)
  1584. {
  1585. if ( pDebugPrints->m_dwOutputFlags & DbgOutputStderr) {
  1586. DWORD nBytesWritten;
  1587. ( VOID) WriteFile( pDebugPrints->m_StdErrHandle,
  1588. pszDump,
  1589. cbDump,
  1590. &nBytesWritten,
  1591. NULL);
  1592. }
  1593. if ( pDebugPrints->m_dwOutputFlags & DbgOutputLogFile &&
  1594. pDebugPrints->m_LogFileHandle != INVALID_HANDLE_VALUE) {
  1595. DWORD nBytesWritten;
  1596. //
  1597. // Truncation of log files. Not yet implemented.
  1598. ( VOID) WriteFile( pDebugPrints->m_LogFileHandle,
  1599. pszDump,
  1600. cbDump,
  1601. &nBytesWritten,
  1602. NULL);
  1603. }
  1604. }
  1605. if ( pDebugPrints == NULL
  1606. || pDebugPrints->m_dwOutputFlags & DbgOutputKdb)
  1607. {
  1608. OutputDebugString( pszDump);
  1609. }
  1610. SetLastError( dwErr );
  1611. return;
  1612. } // PuDbgDump()
  1613. //
  1614. // N.B. For PuDbgCaptureContext() to work properly, the calling function
  1615. // *must* be __cdecl, and must have a "normal" stack frame. So, we decorate
  1616. // PuDbgAssertFailed() with the __cdecl modifier and disable the frame pointer
  1617. // omission (FPO) optimization.
  1618. //
  1619. #pragma optimize( "y", off ) // disable frame pointer omission (FPO)
  1620. VOID
  1621. __cdecl
  1622. PuDbgAssertFailed(
  1623. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1624. IN const char * pszFilePath,
  1625. IN int nLineNum,
  1626. IN const char * pszExpression,
  1627. IN const char * pszMessage)
  1628. /*++
  1629. This function calls assertion failure and records assertion failure
  1630. in log file.
  1631. --*/
  1632. {
  1633. CONTEXT context;
  1634. PuDbgCaptureContext( &context );
  1635. PuDbgPrint( pDebugPrints, pszFilePath, nLineNum,
  1636. " Assertion (%s) Failed: %s\n"
  1637. " use !cxr %p to dump context\n",
  1638. pszExpression,
  1639. pszMessage,
  1640. &context);
  1641. if (( NULL == pDebugPrints) || (TRUE == pDebugPrints->m_fBreakOnAssert))
  1642. {
  1643. DebugBreak();
  1644. }
  1645. return;
  1646. } // PuDbgAssertFailed()
  1647. #pragma optimize( "", on ) // restore frame pointer omission (FPO)
  1648. dllexp VOID
  1649. PuDbgPrintCurrentTime(
  1650. IN OUT LPDEBUG_PRINTS pDebugPrints,
  1651. IN const char * pszFilePath,
  1652. IN int nLineNum
  1653. )
  1654. /*++
  1655. This function generates the current time and prints it out to debugger
  1656. for tracing out the path traversed, if need be.
  1657. Arguments:
  1658. pszFile pointer to string containing the name of the file
  1659. lineNum line number within the file where this function is called.
  1660. Returns:
  1661. NO_ERROR always.
  1662. --*/
  1663. {
  1664. PuDbgPrint( pDebugPrints, pszFilePath, nLineNum,
  1665. " TickCount = %u\n",
  1666. GetTickCount()
  1667. );
  1668. return;
  1669. } // PrintOutCurrentTime()
  1670. dllexp DWORD
  1671. PuLoadDebugFlagsFromReg(IN HKEY hkey, IN DWORD dwDefault, IN LPDEBUG_PRINTS pDebugPrints)
  1672. /*++
  1673. This function reads the debug flags assumed to be stored in
  1674. the location "DebugFlags" under given key.
  1675. If there is any error the default value is returned.
  1676. --*/
  1677. {
  1678. DWORD err;
  1679. DWORD dwDebug = dwDefault;
  1680. DWORD dwBuffer;
  1681. DWORD cbBuffer = sizeof(dwBuffer);
  1682. DWORD dwType;
  1683. if( hkey != NULL )
  1684. {
  1685. err = RegQueryValueExA( hkey,
  1686. DEBUG_FLAGS_REGISTRY_LOCATION_A,
  1687. NULL,
  1688. &dwType,
  1689. (LPBYTE)&dwBuffer,
  1690. &cbBuffer );
  1691. if( ( err == NO_ERROR ) && ( dwType == REG_DWORD ) )
  1692. {
  1693. dwDebug = dwBuffer;
  1694. }
  1695. cbBuffer = sizeof(DWORD);
  1696. if (pDebugPrints)
  1697. {
  1698. err = RegQueryValueExA( hkey,
  1699. DEBUG_BREAK_ENABLED_REGKEYNAME_A,
  1700. NULL,
  1701. &dwType,
  1702. (LPBYTE)&dwBuffer,
  1703. &cbBuffer );
  1704. if( ( err == NO_ERROR ) && ( dwType == REG_DWORD ) )
  1705. {
  1706. pDebugPrints->m_fBreakOnAssert = dwBuffer;
  1707. }
  1708. }
  1709. }
  1710. return dwDebug;
  1711. } // PuLoadDebugFlagsFromReg()
  1712. dllexp DWORD
  1713. PuLoadDebugFlagsFromRegStr(IN LPCSTR pszRegKey, IN DWORD dwDefault, IN LPDEBUG_PRINTS pDebugPrints)
  1714. /*++
  1715. Description:
  1716. This function reads the debug flags assumed to be stored in
  1717. the location "DebugFlags" under given key location in registry.
  1718. If there is any error the default value is returned.
  1719. Arguments:
  1720. pszRegKey - pointer to registry key location from where to read the key from
  1721. dwDefault - default values in case the read from registry fails
  1722. Returns:
  1723. Newly read value on success
  1724. If there is any error the dwDefault is returned.
  1725. --*/
  1726. {
  1727. HKEY hkey = NULL;
  1728. DWORD dwVal = dwDefault;
  1729. DWORD dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1730. pszRegKey,
  1731. 0,
  1732. KEY_ALL_ACCESS,
  1733. &hkey);
  1734. if ( dwError == NO_ERROR) {
  1735. dwVal = PuLoadDebugFlagsFromReg( hkey, dwDefault, pDebugPrints);
  1736. RegCloseKey( hkey);
  1737. hkey = NULL;
  1738. }
  1739. return ( dwVal);
  1740. } // PuLoadDebugFlagsFromRegStr()
  1741. dllexp DWORD
  1742. PuSaveDebugFlagsInReg(IN HKEY hkey, IN DWORD dwDbg)
  1743. /*++
  1744. Saves the debug flags in registry. On failure returns the error code for
  1745. the operation that failed.
  1746. --*/
  1747. {
  1748. DWORD err;
  1749. if( hkey == NULL ) {
  1750. err = ERROR_INVALID_PARAMETER;
  1751. } else {
  1752. err = RegSetValueExA(hkey,
  1753. DEBUG_FLAGS_REGISTRY_LOCATION_A,
  1754. 0,
  1755. REG_DWORD,
  1756. (LPBYTE)&dwDbg,
  1757. sizeof(dwDbg) );
  1758. }
  1759. return (err);
  1760. } // PuSaveDebugFlagsInReg()
  1761. #endif // !_NO_TRACING_
  1762. VOID
  1763. PuDbgCaptureContext (
  1764. OUT PCONTEXT ContextRecord
  1765. )
  1766. {
  1767. RtlCaptureContext(ContextRecord);
  1768. return;
  1769. } // PuDbgCaptureContext
  1770. /****************************** End of File ******************************/