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.

2209 lines
111 KiB

  1. /****************************************************************************/
  2. /* ntrcint.c */
  3. /* */
  4. /* Internal tracing functions - Windows NT specific */
  5. /* */
  6. /* Copyright(C) Microsoft Corporation 1997-1998 */
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. /****************************************************************************/
  10. /* Define TRC_FILE and TRC_GROUP. */
  11. /****************************************************************************/
  12. #undef TRC_FILE
  13. #define TRC_FILE "ntrcint"
  14. #define TRC_GROUP TRC_GROUP_TRACE
  15. /****************************************************************************/
  16. /* Trace specific includes. */
  17. /****************************************************************************/
  18. #include <atrcapi.h>
  19. #include <atrcint.h>
  20. #ifndef OS_WINCE
  21. #include <imagehlp.h>
  22. #endif
  23. #include <ndcgver.h>
  24. /****************************************************************************/
  25. /* */
  26. /* DATA */
  27. /* */
  28. /****************************************************************************/
  29. #define DC_INCLUDE_DATA
  30. #include <atrcdata.c>
  31. #undef DC_INCLUDE_DATA
  32. /****************************************************************************/
  33. /* */
  34. /* FUNCTIONS */
  35. /* */
  36. /****************************************************************************/
  37. /****************************************************************************/
  38. /* FUNCTION: DllMain(...) */
  39. /* */
  40. /* DESCRIPTION: */
  41. /* ============ */
  42. /* Entry/exit point for the trace DLL. This function is called whenever a */
  43. /* process or thread attaches or detaches from this DLL. */
  44. /* */
  45. /* PARAMETERS: */
  46. /* =========== */
  47. /* hModule : a module handle. */
  48. /* reasonForCall : an enumerated type that indicates which of the four */
  49. /* reasons the DLLMain function is being called: process */
  50. /* attach, thread attach, thread detach or process */
  51. /* detach. */
  52. /* lpReserved : unused. */
  53. /* */
  54. /* RETURNS: */
  55. /* ======== */
  56. /* TRUE if the attachment succeeds and FALSE otherwise. */
  57. /* */
  58. /****************************************************************************/
  59. #ifndef STATICONLY
  60. int APIENTRY DllMain(HANDLE hModule,
  61. DWORD reasonForCall,
  62. LPVOID lpReserved)
  63. {
  64. DCBOOL retValue = TRUE;
  65. DCUINT rc = 0;
  66. DC_IGNORE_PARAMETER(lpReserved);
  67. #ifdef OS_WINCE
  68. DC_IGNORE_PARAMETER(hModule);
  69. #endif // OS_WINCE
  70. /************************************************************************/
  71. /* Determine the reason for the call. Note that anything we do in here */
  72. /* is thread safe as we implicitly have the process critical section. */
  73. /************************************************************************/
  74. switch (reasonForCall)
  75. {
  76. #ifndef OS_WINCE
  77. /********************************************************************/
  78. /* A process is attaching to this DLL. */
  79. /********************************************************************/
  80. case DLL_PROCESS_ATTACH:
  81. {
  82. /****************************************************************/
  83. /* Call the internal function to initialize the trace DLL. */
  84. /* This function sets up the memory mapped shared data, and */
  85. /* opens and initializes the trace files. It may be called */
  86. /* either via a process attach or by the first person to call */
  87. /* the trace DLL. The latter case can only occur if another */
  88. /* DLL performs trace calls in its <DllMain> function and that */
  89. /* DLLs <DllMain> function is called before the trace DLLs */
  90. /* <DllMain> function (i.e. this function!). */
  91. /****************************************************************/
  92. rc = TRC_Initialize(TRUE);
  93. if (0 != rc)
  94. {
  95. retValue = FALSE;
  96. DC_QUIT;
  97. }
  98. /****************************************************************/
  99. /* Save the module handle. */
  100. /****************************************************************/
  101. trchModule = hModule;
  102. /****************************************************************/
  103. /* Get the trace DLL module file name. We use this later when */
  104. /* we get a stack trace. */
  105. /****************************************************************/
  106. if ( TRCGetModuleFileName(
  107. trcpSharedData->trcpModuleFileName,
  108. SIZE_TCHARS(trcpSharedData->trcpModuleFileName)) !=
  109. DC_RC_OK )
  110. {
  111. retValue = FALSE;
  112. DC_QUIT;
  113. }
  114. /****************************************************************/
  115. /* A process is attaching so trace this fact out. */
  116. /****************************************************************/
  117. TRCInternalTrace(TRC_PROCESS_ATTACH_NOTIFY);
  118. }
  119. break;
  120. /********************************************************************/
  121. /* A process is detaching from this DLL. */
  122. /********************************************************************/
  123. case DLL_PROCESS_DETACH:
  124. {
  125. /****************************************************************/
  126. /* Write out the process detach trace line. */
  127. /****************************************************************/
  128. TRCInternalTrace(TRC_PROCESS_DETACH_NOTIFY);
  129. /****************************************************************/
  130. /* Call the trace DLL termination function. This will close */
  131. /* all files, free the shared data and then close the mutex */
  132. /* handle. */
  133. /****************************************************************/
  134. TRC_Terminate(TRUE);
  135. }
  136. break;
  137. /********************************************************************/
  138. /* A thread is attaching to this DLL. */
  139. /********************************************************************/
  140. case DLL_THREAD_ATTACH:
  141. {
  142. /****************************************************************/
  143. /* Write out the thread attach trace line. */
  144. /****************************************************************/
  145. TRCInternalTrace(TRC_THREAD_ATTACH_NOTIFY);
  146. }
  147. break;
  148. /********************************************************************/
  149. /* A thread is detaching from this DLL. */
  150. /********************************************************************/
  151. case DLL_THREAD_DETACH:
  152. {
  153. /****************************************************************/
  154. /* Write out the thread detach trace line. */
  155. /****************************************************************/
  156. TRCInternalTrace(TRC_THREAD_DETACH_NOTIFY);
  157. }
  158. break;
  159. #endif // OS_WINCE
  160. }
  161. /************************************************************************/
  162. /* Now return the appropriate return value. NT currently only checks */
  163. /* the value for the DLL_PROCESS_ATTACH case - if it is false then the */
  164. /* app will fail to initialize. */
  165. /************************************************************************/
  166. DC_EXIT_POINT:
  167. return(retValue);
  168. } /* DllMain */
  169. #endif
  170. /****************************************************************************/
  171. /* FUNCTION: TRCBlankFile(...) */
  172. /* */
  173. /* DESCRIPTION: */
  174. /* ============ */
  175. /* This function fills the specified trace file with spaces. */
  176. /* */
  177. /* PARAMETERS: */
  178. /* =========== */
  179. /* fileNumber : which file to blank. */
  180. /* */
  181. /* RETURNS: */
  182. /* ======== */
  183. /* Nothing. */
  184. /* */
  185. /****************************************************************************/
  186. DCVOID DCINTERNAL TRCBlankFile(DCUINT fileNumber)
  187. {
  188. /************************************************************************/
  189. /* Use DC_MEMSET to fill the file with spaces. */
  190. /************************************************************************/
  191. DC_MEMSET(trcpFiles[fileNumber], '\0', trcpConfig->maxFileSize);
  192. /************************************************************************/
  193. /* Finally flush this change to disk. Setting the second parameter to */
  194. /* zero flushes the whole file to disk. */
  195. /************************************************************************/
  196. FlushViewOfFile(trcpFiles[fileNumber], 0);
  197. return;
  198. } /* TRC_BlankFile */
  199. /****************************************************************************/
  200. /* FUNCTION: TRCCloseSharedData(...) */
  201. /* */
  202. /* DESCRIPTION: */
  203. /* ============ */
  204. /* This function closes the shared data memory mapped file. */
  205. /* */
  206. /* PARAMETERS: */
  207. /* =========== */
  208. /* None. */
  209. /* */
  210. /* RETURNS: */
  211. /* ======== */
  212. /* Nothing. */
  213. /* */
  214. /****************************************************************************/
  215. DCVOID DCINTERNAL TRCCloseSharedData(DCVOID)
  216. {
  217. /************************************************************************/
  218. /* Now we need to unmap our view of the file. */
  219. /************************************************************************/
  220. UnmapViewOfFile(trcpSharedData);
  221. trcpSharedData = NULL;
  222. /************************************************************************/
  223. /* Now close the handle to the file mapping object. */
  224. /************************************************************************/
  225. CloseHandle(trchSharedDataObject);
  226. trchSharedDataObject = NULL;
  227. /************************************************************************/
  228. /* NULL our static pointer to the shared configuration data. */
  229. /************************************************************************/
  230. trcpConfig = NULL;
  231. /************************************************************************/
  232. /* That's it so just return. */
  233. /************************************************************************/
  234. return;
  235. } /* TRCCloseSharedData */
  236. /****************************************************************************/
  237. /* FUNCTION: TRCCloseSingleFile(...) */
  238. /* */
  239. /* DESCRIPTION: */
  240. /* ============ */
  241. /* Closes a single trace memory mapped file. */
  242. /* */
  243. /* PARAMETERS: */
  244. /* =========== */
  245. /* fileNumber : which file to close. */
  246. /* seconds : value to set the seconds time stamp of the file to. */
  247. /* */
  248. /* RETURNS: */
  249. /* ======== */
  250. /* Nothing. */
  251. /* */
  252. /****************************************************************************/
  253. DCVOID DCINTERNAL TRCCloseSingleFile(DCUINT fileNumber, DCUINT seconds)
  254. {
  255. FILETIME fileTime;
  256. SYSTEMTIME systemTime;
  257. DCUINT32 offset;
  258. /************************************************************************/
  259. /* We need to reset the size of this file - we do this by determining */
  260. /* the trace file offset. Make sure that we do this before we unmap */
  261. /* the file. */
  262. /************************************************************************/
  263. offset = TRCDetermineOffset(fileNumber);
  264. /************************************************************************/
  265. /* Unmap the view of the file. */
  266. /************************************************************************/
  267. UnmapViewOfFile(trcpFiles[fileNumber]);
  268. trcpFiles[fileNumber] = NULL;
  269. /************************************************************************/
  270. /* Free up the handle to the file mapping object. */
  271. /************************************************************************/
  272. CloseHandle(trchMappingObjects[fileNumber]);
  273. trchMappingObjects[fileNumber] = NULL;
  274. /************************************************************************/
  275. /* Now set the file pointer to the end of all the trace text and then */
  276. /* set the end of the file to this position. */
  277. /************************************************************************/
  278. SetFilePointer(trchFileObjects[fileNumber],
  279. offset,
  280. NULL,
  281. FILE_BEGIN);
  282. SetEndOfFile(trchFileObjects[fileNumber]);
  283. /************************************************************************/
  284. /* Now we have to do something a little messy - the file time is not */
  285. /* properly updated when the memory mapped file is closed and we rely */
  286. /* on the file time to decide which file to start tracing to at the */
  287. /* start of day. Therefore we need to force the system to update the */
  288. /* file times using SetFileTime (we set the created, modified and */
  289. /* accessed times). On NT4.0 this does not guarantee that the times */
  290. /* are the same - one file had a created time of 16:35:16 and a */
  291. /* modified time of 16:35:18 after a call to SetFileTime! Files only */
  292. /* have a time resolution of two seconds if they are stored on a FAT */
  293. /* partition by NT. */
  294. /************************************************************************/
  295. GetSystemTime(&systemTime);
  296. /************************************************************************/
  297. /* Set the number of seconds of the file. */
  298. /************************************************************************/
  299. systemTime.wSecond = (WORD) seconds;
  300. /************************************************************************/
  301. /* Now convert the system time to a file time and update the file time. */
  302. /************************************************************************/
  303. SystemTimeToFileTime(&systemTime, &fileTime);
  304. SetFileTime(trchFileObjects[fileNumber], &fileTime, &fileTime, &fileTime);
  305. /************************************************************************/
  306. /* Close the file handle. */
  307. /************************************************************************/
  308. CloseHandle(trchFileObjects[fileNumber]);
  309. trchFileObjects[fileNumber] = NULL;
  310. return;
  311. } /* TRCCloseSingleFile */
  312. /****************************************************************************/
  313. /* FUNCTION: TRCDetermineIndicator(...) */
  314. /* */
  315. /* DESCRIPTION: */
  316. /* ============ */
  317. /* This function sets the trace file indicator as follows: */
  318. /* */
  319. /* - No trace files exist : indicator set to 0 */
  320. /* - One trace file exists : indicator set to the existing file (0 or 1) */
  321. /* - Both trace files exist : indicator set to the newer file. */
  322. /* */
  323. /* PARAMETERS: */
  324. /* =========== */
  325. /* None. */
  326. /* */
  327. /* RETURNS: */
  328. /* ======== */
  329. /* Nothing. */
  330. /* */
  331. /****************************************************************************/
  332. DCVOID DCINTERNAL TRCDetermineIndicator(DCVOID)
  333. {
  334. DCINT i;
  335. DCBOOL rc[TRC_NUM_FILES];
  336. DCINT32 tdRC;
  337. FILETIME fileTime[TRC_NUM_FILES];
  338. /************************************************************************/
  339. /* We also need to set up the trace file indicator. By default we use */
  340. /* trace file 0. */
  341. /************************************************************************/
  342. trcpSharedData->trcIndicator = 0;
  343. /************************************************************************/
  344. /* Determine the most recent trace file. Use GetFileTime to get the */
  345. /* date and time of this file. */
  346. /************************************************************************/
  347. for (i = 0; i < TRC_NUM_FILES; i++)
  348. {
  349. rc[i] = TRCGetFileTime(i, &(fileTime[i]));
  350. }
  351. /************************************************************************/
  352. /* Now check to see which file we should return based on the following */
  353. /* options: */
  354. /* */
  355. /* �������������������������������������������Ŀ */
  356. /* � File 0 exists � File 1 exists � return � */
  357. /* �������������������������������������������Ĵ */
  358. /* � No � No � file 0 � */
  359. /* � No � Yes � file 1 � */
  360. /* � Yes � Yes � compare � */
  361. /* � Yes � No � file 0 � */
  362. /* ��������������������������������������������� */
  363. /************************************************************************/
  364. /************************************************************************/
  365. /* If file 1 does not exist then we return file 0 regardless. */
  366. /************************************************************************/
  367. if (FALSE == rc[1])
  368. {
  369. DC_QUIT;
  370. }
  371. /************************************************************************/
  372. /* If file 0 does not exist and file 1 does, then return file 1. */
  373. /************************************************************************/
  374. if ((FALSE == rc[0]) && (TRUE == rc[1]))
  375. {
  376. trcpSharedData->trcIndicator = 1;
  377. DC_QUIT;
  378. }
  379. /************************************************************************/
  380. /* If we have got this far then both trace files exist so we need to */
  381. /* make a decision based on their ages. User the Win32 CompareFileTime */
  382. /* function to do this. */
  383. /************************************************************************/
  384. tdRC = CompareFileTime(&(fileTime[0]), &(fileTime[1]));
  385. /************************************************************************/
  386. /* If the file times are equal or the first file is newer than the */
  387. /* second then select file 0 (i.e. just quit). */
  388. /************************************************************************/
  389. if (tdRC >= 0)
  390. {
  391. DC_QUIT;
  392. }
  393. /************************************************************************/
  394. /* If we get here then file 1 is newer than file 0 so set the indicator */
  395. /* to file 1. */
  396. /************************************************************************/
  397. trcpSharedData->trcIndicator = 1;
  398. DC_EXIT_POINT:
  399. return;
  400. } /* TRCDetermineIndicator */
  401. /****************************************************************************/
  402. /* FUNCTION: TRCDetermineOffset(...) */
  403. /* */
  404. /* DESCRIPTION: */
  405. /* ============ */
  406. /* This function determines the end-of-file offset in the selected trace */
  407. /* file. */
  408. /* */
  409. /* PARAMETERS: */
  410. /* =========== */
  411. /* fileNum : the number of the file to determine the offset for. */
  412. /* */
  413. /* RETURNS: */
  414. /* ======== */
  415. /* The offset in that file. */
  416. /* */
  417. /****************************************************************************/
  418. DCUINT32 DCINTERNAL TRCDetermineOffset(DCUINT32 fileNum)
  419. {
  420. DCUINT32 retVal;
  421. PDCTCHAR pTemp;
  422. PDCUINT8 pWork;
  423. /************************************************************************/
  424. /* Set the temporary pointer to point at the end of the trace file. */
  425. /************************************************************************/
  426. pWork = (PDCUINT8)(trcpFiles[fileNum]);
  427. if(NULL == pWork)
  428. {
  429. return 0;
  430. }
  431. pWork += trcpConfig->maxFileSize - sizeof(DCTCHAR);
  432. pTemp = (PDCTCHAR)pWork;
  433. /************************************************************************/
  434. /* Now run back through the trace file looking for the first non-space */
  435. /* character. */
  436. /************************************************************************/
  437. while ((pTemp >= trcpFiles[fileNum]) &&
  438. (_T('\0') == *pTemp))
  439. {
  440. pTemp--;
  441. }
  442. /************************************************************************/
  443. /* Increment forward to the next blank character. It does not matter */
  444. /* if we increment past the end of the file as we check whether we need */
  445. /* to flip the trace files everytime we write a trace line. */
  446. /************************************************************************/
  447. pTemp++;
  448. /************************************************************************/
  449. /* Now set the offset correctly. */
  450. /************************************************************************/
  451. retVal = (DCUINT32)(pTemp - trcpFiles[fileNum]);
  452. return(retVal);
  453. } /* TRCDetermineOffset */
  454. /****************************************************************************/
  455. /* FUNCTION: TRCExitProcess(...) */
  456. /* */
  457. /* DESCRIPTION: */
  458. /* ============ */
  459. /* This function kills the current process. */
  460. /* */
  461. /* PARAMETERS: */
  462. /* =========== */
  463. /* exitCode : exit code for the terminating process */
  464. /* */
  465. /* RETURNS: */
  466. /* ======== */
  467. /* Nothing. */
  468. /* */
  469. /****************************************************************************/
  470. DCVOID DCINTERNAL TRCExitProcess(DCUINT32 exitCode)
  471. {
  472. #ifndef OS_WINCE
  473. ExitProcess(exitCode);
  474. #else
  475. //BUGBUG this is broken if not called from the main
  476. //thread.
  477. ExitThread(exitCode);
  478. #endif
  479. }
  480. /****************************************************************************/
  481. /* FUNCTION: TRCGetCurrentDate(...) */
  482. /* */
  483. /* DESCRIPTION: */
  484. /* ============ */
  485. /* This function gets the current local date and returns it in a DC_DATE */
  486. /* structure. */
  487. /* */
  488. /* PARAMETERS: */
  489. /* =========== */
  490. /* pDate : a pointer to a DC_DATE structure. */
  491. /* */
  492. /* RETURNS: */
  493. /* ======== */
  494. /* Nothing. */
  495. /* */
  496. /****************************************************************************/
  497. DCVOID DCINTERNAL TRCGetCurrentDate(PDC_DATE pDate)
  498. {
  499. SYSTEMTIME systemTime;
  500. /************************************************************************/
  501. /* Call the Win32 API function to get the current time. */
  502. /************************************************************************/
  503. GetLocalTime(&systemTime);
  504. /************************************************************************/
  505. /* Reformat the date into a DC_DATE structure. */
  506. /************************************************************************/
  507. pDate->day = (DCUINT8) systemTime.wDay;
  508. pDate->month = (DCUINT8) systemTime.wMonth;
  509. pDate->year = (DCUINT16) systemTime.wYear;
  510. } /* TRCGetCurrentDate */
  511. /****************************************************************************/
  512. /* FUNCTION: TRCGetCurrentTime(...) */
  513. /* */
  514. /* DESCRIPTION: */
  515. /* ============ */
  516. /* This function gets the current local time and returns it in a DC_TIME */
  517. /* structure. */
  518. /* */
  519. /* PARAMETERS: */
  520. /* =========== */
  521. /* pTime : a pointer to a DC_TIME structure. */
  522. /* */
  523. /* RETURNS: */
  524. /* ======== */
  525. /* Nothing. */
  526. /* */
  527. /****************************************************************************/
  528. DCVOID DCINTERNAL TRCGetCurrentTime(PDC_TIME pTime)
  529. {
  530. SYSTEMTIME systemTime;
  531. /************************************************************************/
  532. /* Call the Win32 API function to get the current time. */
  533. /************************************************************************/
  534. GetLocalTime(&systemTime);
  535. /************************************************************************/
  536. /* Reformat the time into a DC_TIME structure. */
  537. /************************************************************************/
  538. pTime->hour = (DCUINT8)systemTime.wHour;
  539. pTime->min = (DCUINT8)systemTime.wMinute;
  540. pTime->sec = (DCUINT8)systemTime.wSecond;
  541. pTime->hundredths = (DCUINT8)(systemTime.wMilliseconds / 10);
  542. } /* TRCGetCurrentTime */
  543. /****************************************************************************/
  544. /* FUNCTION: TRCGetFileTime(...) */
  545. /* */
  546. /* DESCRIPTION: */
  547. /* ============ */
  548. /* This function tests if the specified file exists - if it does it */
  549. /* returns TRUE and fills in pFileTime with a FILETIME structure. If the */
  550. /* file does not exist it returns FALSE. */
  551. /* */
  552. /* PARAMETERS: */
  553. /* =========== */
  554. /* fileNumber : number of file to query. */
  555. /* pFileTime : a pointer to a FILETIME structure. */
  556. /* */
  557. /* RETURNS: */
  558. /* ======== */
  559. /* Nothing. */
  560. /* */
  561. /****************************************************************************/
  562. DCBOOL DCINTERNAL TRCGetFileTime(DCUINT fileNumber,
  563. PDCFILETIME pFileTime)
  564. {
  565. DCBOOL rc = FALSE;
  566. HANDLE hFile;
  567. /************************************************************************/
  568. /* Attempt to open the file. By specifying OPEN_EXISITING, we only try */
  569. /* to open an existing file - the call will fail if the file doesn't */
  570. /* already exist. */
  571. /************************************************************************/
  572. hFile = CreateFile(trcpConfig->fileNames[fileNumber],
  573. GENERIC_READ,
  574. FILE_SHARE_READ,
  575. NULL,
  576. OPEN_EXISTING,
  577. FILE_ATTRIBUTE_NORMAL,
  578. NULL);
  579. /************************************************************************/
  580. /* Now check to see if the file exists - if it is invalid then the file */
  581. /* doesn't exist. */
  582. /************************************************************************/
  583. if (INVALID_HANDLE_VALUE == hFile)
  584. {
  585. /********************************************************************/
  586. /* The file doesn't exist so return FALSE. */
  587. /********************************************************************/
  588. DC_QUIT;
  589. }
  590. /************************************************************************/
  591. /* Determine the most recent trace file. Use GetFileTime to get the */
  592. /* date and time of this file. */
  593. /************************************************************************/
  594. rc = GetFileTime(hFile, NULL, NULL, pFileTime);
  595. /************************************************************************/
  596. /* Finally close the file handle. */
  597. /************************************************************************/
  598. CloseHandle(hFile);
  599. DC_EXIT_POINT:
  600. return(rc);
  601. } /* TRCGetFileTime */
  602. /****************************************************************************/
  603. /* FUNCTION: TRCSystemError(...) */
  604. /* */
  605. /* DESCRIPTION: */
  606. /* ============ */
  607. /* This function obtains the value of the system error flag and outputs it */
  608. /* to the trace file as an alert level trace. */
  609. /* */
  610. /* Note that NT maintains the last system error on a per-thread basis and */
  611. /* that most Win32 API function calls set it if they fail. */
  612. /* */
  613. /* PARAMETERS: */
  614. /* =========== */
  615. /* traceComponent : the trace component. */
  616. /* lineNumber : the line number. */
  617. /* funcName : the function name. */
  618. /* fileName : the file name. */
  619. /* */
  620. /* RETURNS: */
  621. /* ======== */
  622. /* Nothing. */
  623. /* */
  624. /****************************************************************************/
  625. DCVOID DCINTERNAL TRCSystemError(DCUINT traceComponent,
  626. DCUINT lineNumber,
  627. PDCTCHAR funcName,
  628. PDCTCHAR fileName,
  629. PDCTCHAR string)
  630. {
  631. DCUINT32 length;
  632. DWORD lastError;
  633. DWORD rc;
  634. HRESULT hr;
  635. /************************************************************************/
  636. /* Get the last system error for this thread. We will restore this at */
  637. /* the end of this function. */
  638. /************************************************************************/
  639. lastError = GetLastError();
  640. /************************************************************************/
  641. /* Grab the mutex. */
  642. /************************************************************************/
  643. TRCGrabMutex();
  644. /************************************************************************/
  645. /* The output string will be of the format: */
  646. /* */
  647. /* SYSTEM ERROR in <System Call>, <id of error> , <associated string> */
  648. /* */
  649. /* So create the first entry in the string. */
  650. /************************************************************************/
  651. hr = StringCchPrintf(trcpOutputBuffer,
  652. TRC_LINE_BUFFER_SIZE,
  653. _T("SYSTEM ERROR in %s, %d, "),
  654. string,
  655. lastError);
  656. if (SUCCEEDED(hr)) {
  657. length = DC_TSTRLEN(trcpOutputBuffer);
  658. rc = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  659. NULL,
  660. lastError,
  661. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  662. &(trcpOutputBuffer[length]),
  663. TRC_LINE_BUFFER_SIZE - length * sizeof(DCTCHAR),
  664. NULL);
  665. }
  666. else {
  667. DC_QUIT;
  668. }
  669. /************************************************************************/
  670. /* Check the return code. */
  671. /************************************************************************/
  672. if (0 == rc)
  673. {
  674. hr = StringCchPrintf(trcpOutputBuffer + length,
  675. TRC_LINE_BUFFER_SIZE - length -1,
  676. _T("<FormatMessage> failed with rc %#hx"),
  677. GetLastError());
  678. if (FAILED(hr)) {
  679. DC_QUIT;
  680. }
  681. }
  682. else
  683. {
  684. /********************************************************************/
  685. /* <FormatMessage> adds an additional '\r\n' to the end of the */
  686. /* message string - however we don't need this so we strip it off. */
  687. /********************************************************************/
  688. length = DC_TSTRLEN(trcpOutputBuffer);
  689. trcpOutputBuffer[length - 2] = _T('\0');
  690. }
  691. /************************************************************************/
  692. /* Now call our internal trace buffer function to trace this message */
  693. /* out. Note that we don't need to worry about freeing the mutex - */
  694. /* <TRC_TraceBuffer> will do that for us. */
  695. /************************************************************************/
  696. TRC_TraceBuffer(TRC_LEVEL_ALT,
  697. traceComponent,
  698. lineNumber,
  699. funcName,
  700. fileName);
  701. DC_EXIT_POINT:
  702. /************************************************************************/
  703. /* Finally we will restore the original value of last error. */
  704. /************************************************************************/
  705. SetLastError(lastError);
  706. return;
  707. } /* TRCSystemError */
  708. /****************************************************************************/
  709. /* FUNCTION: TRCOpenAllFiles(...) */
  710. /* */
  711. /* DESCRIPTION: */
  712. /* ============ */
  713. /* Opens all the trace files. */
  714. /* */
  715. /* PARAMETERS: */
  716. /* =========== */
  717. /* None. */
  718. /* */
  719. /* RETURNS: */
  720. /* ======== */
  721. /* 0 : Function succeeded. */
  722. /* */
  723. /****************************************************************************/
  724. DCUINT DCINTERNAL TRCOpenAllFiles(DCVOID)
  725. {
  726. DCUINT rc = 0;
  727. DCUINT i;
  728. DCUINT j;
  729. /************************************************************************/
  730. /* Now if we are the first process to attach then set up the trace */
  731. /* indicator. This tells us which file is currently active (i.e. */
  732. /* being used for trace output). We need to do this before we open the */
  733. /* files as if they both exist already, they will both be created. */
  734. /* File 2 will be created after file 1 and as we trace to the most */
  735. /* recent file we will end up tracing to file 2 - and you don't want to */
  736. /* do that! */
  737. /************************************************************************/
  738. if (trcCreatedTraceFiles)
  739. {
  740. TRCDetermineIndicator();
  741. }
  742. /************************************************************************/
  743. /* Open all the trace output files. */
  744. /************************************************************************/
  745. for (i = 0; i < TRC_NUM_FILES; i++)
  746. {
  747. /********************************************************************/
  748. /* Call TRCOpenSingleFile to open a single trace file. */
  749. /********************************************************************/
  750. rc = TRCOpenSingleFile(i);
  751. if (0 != rc)
  752. {
  753. DC_QUIT;
  754. }
  755. }
  756. /************************************************************************/
  757. /* Finally, if we are the first process to attach, then set up the */
  758. /* trace offset. This is the offset within the currently active trace */
  759. /* file. */
  760. /************************************************************************/
  761. if (trcCreatedTraceFiles)
  762. {
  763. trcpSharedData->trcOffset =
  764. TRCDetermineOffset(trcpSharedData->trcIndicator);
  765. }
  766. DC_EXIT_POINT:
  767. if (0 != rc)
  768. {
  769. /********************************************************************/
  770. /* Close any files that we may already have opened. We do not need */
  771. /* to call TRCCloseSingleFile for the file which failed to open */
  772. /* correctly as TRCOpenSingleFile will tidy up that file for us. */
  773. /********************************************************************/
  774. for (j = i; j > 0; j--)
  775. {
  776. TRCCloseSingleFile(j - 1, 0);
  777. }
  778. /********************************************************************/
  779. /* Clear the trace-to-file flag - we can't do it. */
  780. /********************************************************************/
  781. CLEAR_FLAG(trcpConfig->flags, TRC_OPT_FILE_OUTPUT);
  782. }
  783. /************************************************************************/
  784. /* Always return 0 to allow tracing to continue to the debugger. */
  785. /************************************************************************/
  786. return(0);
  787. } /* TRCOpenAllFiles */
  788. /****************************************************************************/
  789. /* FUNCTION: TRCOpenSharedData(...) */
  790. /* */
  791. /* DESCRIPTION: */
  792. /* ============ */
  793. /* This function opens the shared data memory mapped file. */
  794. /* */
  795. /* PARAMETERS: */
  796. /* =========== */
  797. /* None. */
  798. /* */
  799. /* RETURNS: */
  800. /* ======== */
  801. /* 0 : Function succeeded */
  802. /* TRC_RC_CREATE_MAPPING_FAILED : Failed to create the file mapping */
  803. /* TRC_RC_MAP_VIEW_FAILED : MapViewOfFile failed. */
  804. /* */
  805. /****************************************************************************/
  806. DCUINT DCINTERNAL TRCOpenSharedData(DCVOID)
  807. {
  808. DCUINT rc = 0;
  809. #ifdef RUN_ON_WINNT
  810. DWORD dwrc;
  811. #endif
  812. #ifndef OS_WINCE
  813. OSVERSIONINFO ver;
  814. SECURITY_ATTRIBUTES sa;
  815. SECURITY_DESCRIPTOR sd;
  816. PSID psidEveryone = NULL;
  817. SID_IDENTIFIER_AUTHORITY sidEveryoneAuthority = SECURITY_WORLD_SID_AUTHORITY;
  818. DCUINT32 dwDaclLength;
  819. PACL pDacl = NULL;
  820. #endif
  821. /************************************************************************/
  822. /* Attempt to create the shared data memory mapped file. If this has */
  823. /* already been created by another instance of this DLL then */
  824. /* CreateFileMapping will simply return the handle of the existing */
  825. /* object. Passing 0xFFFFFFFF creates a shared data memory mapped */
  826. /* file. */
  827. /************************************************************************/
  828. #ifdef OS_WINCE
  829. /************************************************************************/
  830. /* For Windows CE, just use global data; always reset it. Note that */
  831. /* this prevents shared use of the Trace DLL. */
  832. /************************************************************************/
  833. trchSharedDataObject = NULL;
  834. trcpSharedData = &trcSharedData;
  835. trcCreatedTraceFiles = TRUE;
  836. #else
  837. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  838. GetVersionEx(&ver);
  839. if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  840. /************************************************************************/
  841. /* Get the SID for the Everyone group */
  842. /************************************************************************/
  843. if (!AllocateAndInitializeSid (
  844. &sidEveryoneAuthority, // pIdentifierAuthority
  845. 1, // count of subauthorities
  846. SECURITY_WORLD_RID, // subauthority 0
  847. 0, 0, 0, 0, 0, 0, 0, // subauthorities n
  848. &psidEveryone)) { // pointer to pointer to SID
  849. rc = TRC_RC_MAP_VIEW_FAILED;
  850. OutputDebugString(_T("AllocateAndInitializeSid failed.\n"));
  851. DC_QUIT;
  852. }
  853. /************************************************************************/
  854. /* Allocate the Dacl */
  855. /************************************************************************/
  856. dwDaclLength = sizeof(ACL);
  857. dwDaclLength += (sizeof(ACCESS_DENIED_ACE) - sizeof(DWORD)) +
  858. GetLengthSid(psidEveryone);
  859. dwDaclLength += (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  860. GetLengthSid(psidEveryone);
  861. pDacl = (PACL)LocalAlloc(LMEM_FIXED, dwDaclLength);
  862. if (pDacl == NULL) {
  863. OutputDebugString(_T("Can't allocate Dacl.\n"));
  864. rc = TRC_RC_MAP_VIEW_FAILED;
  865. DC_QUIT;
  866. }
  867. /************************************************************************/
  868. /* Initialize it. */
  869. /************************************************************************/
  870. if (!InitializeAcl(pDacl, dwDaclLength, ACL_REVISION)) {
  871. rc = TRC_RC_MAP_VIEW_FAILED;
  872. OutputDebugString(_T("InitializeAcl failed.\n"));
  873. DC_QUIT;
  874. }
  875. /************************************************************************/
  876. /* Allow all access */
  877. /************************************************************************/
  878. if (!AddAccessAllowedAce(
  879. pDacl,
  880. ACL_REVISION,
  881. GENERIC_ALL,
  882. psidEveryone)) {
  883. rc = TRC_RC_MAP_VIEW_FAILED;
  884. OutputDebugString(_T("AddAccessAllowedAce failed.\n"));
  885. DC_QUIT;
  886. }
  887. /************************************************************************/
  888. /* Block Write-DACL Access */
  889. /************************************************************************/
  890. if (!AddAccessDeniedAce(
  891. pDacl,
  892. ACL_REVISION,
  893. WRITE_DAC,
  894. psidEveryone)) {
  895. rc = TRC_RC_MAP_VIEW_FAILED;
  896. OutputDebugString(_T("AddAccessDeniedAceEx failed.\n"));
  897. DC_QUIT;
  898. }
  899. /************************************************************************/
  900. /* Create the File Mapping */
  901. /************************************************************************/
  902. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  903. SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
  904. sa.lpSecurityDescriptor = &sd;
  905. trchSharedDataObject = CreateFileMapping(INVALID_HANDLE_VALUE,
  906. &sa,
  907. PAGE_READWRITE,
  908. 0,
  909. sizeof(TRC_SHARED_DATA),
  910. TRC_SHARED_DATA_NAME);
  911. }
  912. else {
  913. trchSharedDataObject = CreateFileMapping(INVALID_HANDLE_VALUE,
  914. NULL,
  915. PAGE_READWRITE,
  916. 0,
  917. sizeof(TRC_SHARED_DATA),
  918. TRC_SHARED_DATA_NAME);
  919. }
  920. /************************************************************************/
  921. /* Check that we succeeded in creating the file mapping. */
  922. /************************************************************************/
  923. if (NULL == trchSharedDataObject)
  924. {
  925. TRCDebugOutput(_T("NULL trchSharedDataObject.\n"));
  926. rc = TRC_RC_CREATE_MAPPING_FAILED;
  927. DC_QUIT;
  928. }
  929. /************************************************************************/
  930. /* Determine if the file mapping already exists - if it does then we */
  931. /* won't bother reading the registry data in or setting up the file */
  932. /* offset and indicator values. Note that up to this point */
  933. /* <trcCreatedTraceFiles> has been set to TRUE. */
  934. /************************************************************************/
  935. if (ERROR_ALREADY_EXISTS == GetLastError())
  936. {
  937. trcCreatedTraceFiles = FALSE;
  938. }
  939. /************************************************************************/
  940. /* We now have a handle to the shared data MMF which now needs to be */
  941. /* mapped into our address space. Setting the third, fourth and fifth */
  942. /* parameters of MapViewOfFile to zero maps the whole file into our */
  943. /* address space starting with the first byte of the file. */
  944. /************************************************************************/
  945. trcpSharedData = (PTRC_SHARED_DATA) MapViewOfFile(trchSharedDataObject,
  946. FILE_MAP_ALL_ACCESS,
  947. 0,
  948. 0,
  949. 0);
  950. if (NULL == trcpSharedData)
  951. {
  952. /********************************************************************/
  953. /* Free up the handle to the file mapping object. */
  954. /********************************************************************/
  955. CloseHandle(trchSharedDataObject);
  956. trchSharedDataObject = NULL;
  957. /********************************************************************/
  958. /* Output a debug string and then quit. */
  959. /********************************************************************/
  960. TRCDebugOutput(_T("NULL trcpSharedData.\n"));
  961. rc = TRC_RC_MAP_VIEW_FAILED;
  962. DC_QUIT;
  963. }
  964. #endif /* OS_WINCE */
  965. /************************************************************************/
  966. /* Set up our static pointer to the shared configuration data and to */
  967. /* the filter data. */
  968. /************************************************************************/
  969. trcpConfig = &(trcpSharedData->trcConfig);
  970. trcpFilter = &(trcpSharedData->trcFilter);
  971. trcpOutputBuffer = trcpSharedData->trcpOutputBuffer;
  972. /************************************************************************/
  973. /* Finally initialize the shared data block and then read in the */
  974. /* configuration data - but only if we are the first to open the file */
  975. /* mapping. */
  976. /************************************************************************/
  977. if (trcCreatedTraceFiles)
  978. {
  979. /********************************************************************/
  980. /* Initialize the shared data memory mapped file. */
  981. /********************************************************************/
  982. DC_MEMSET(trcpSharedData, 0, sizeof(TRC_SHARED_DATA));
  983. /********************************************************************/
  984. /* Initialize the internal status flags. The following flags apply */
  985. /* to all the processes. */
  986. /********************************************************************/
  987. CLEAR_FLAG(trcpFilter->trcStatus, TRC_STATUS_ASSERT_DISPLAYED);
  988. /********************************************************************/
  989. /* The following flags are maintained on a per-process basis. */
  990. /********************************************************************/
  991. CLEAR_FLAG(trcProcessStatus, TRC_STATUS_SYMBOLS_LOADED);
  992. /********************************************************************/
  993. /* Read in the configuration data. */
  994. /********************************************************************/
  995. TRCReadSharedDataConfig();
  996. /********************************************************************/
  997. /* Now split the prefix list. */
  998. /********************************************************************/
  999. TRCSplitPrefixes();
  1000. }
  1001. DC_EXIT_POINT:
  1002. #ifndef OS_WINCE
  1003. if (pDacl) LocalFree(pDacl);
  1004. if (psidEveryone) FreeSid(psidEveryone);
  1005. #endif
  1006. return(rc);
  1007. } /* TRCOpenSharedData */
  1008. /****************************************************************************/
  1009. /* FUNCTION: TRCOpenSingleFile(...) */
  1010. /* */
  1011. /* DESCRIPTION: */
  1012. /* ============ */
  1013. /* Opens a single trace memory mapped file. */
  1014. /* */
  1015. /* PARAMETERS: */
  1016. /* =========== */
  1017. /* fileNum : which file to open. */
  1018. /* */
  1019. /* RETURNS: */
  1020. /* ======== */
  1021. /* 0 : Function succeeded */
  1022. /* TRC_RC_CREATE_FILE_FAILED : CreateFile call failed */
  1023. /* TRC_RC_MAP_VIEW_FAILED : MapViewOfFile failed */
  1024. /* TRC_RC_CREATE_MAPPING_FAILED : Failed to create the file mapping */
  1025. /* */
  1026. /****************************************************************************/
  1027. DCUINT DCINTERNAL TRCOpenSingleFile(DCUINT fileNum)
  1028. {
  1029. DCUINT rc = 0;
  1030. DCBOOL blankFile = FALSE;
  1031. #ifndef OS_WINCE
  1032. DCTCHAR objectName[30];
  1033. SECURITY_ATTRIBUTES sa;
  1034. SECURITY_DESCRIPTOR sd;
  1035. PSID psidEveryone = NULL;
  1036. SID_IDENTIFIER_AUTHORITY sidEveryoneAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1037. DCUINT32 dwDaclLength;
  1038. PACL pDacl = NULL;
  1039. OSVERSIONINFO ver;
  1040. HRESULT hr;
  1041. #endif
  1042. /************************************************************************/
  1043. /* Open a single trace file. First of all we attempt to open the file */
  1044. /* with read and write access, and shared read and write access. The */
  1045. /* OPEN_ALWAYS flag ensures that the file is created if it does not */
  1046. /* already exist. We pass NULL for the security attributes and */
  1047. /* template parameters (4 and 7). */
  1048. /************************************************************************/
  1049. trchFileObjects[fileNum] = CreateFile(trcpConfig->fileNames[fileNum],
  1050. GENERIC_READ | GENERIC_WRITE,
  1051. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1052. NULL,
  1053. #ifndef OS_WINCE
  1054. OPEN_ALWAYS,
  1055. #else
  1056. CREATE_ALWAYS,
  1057. #endif
  1058. FILE_ATTRIBUTE_NORMAL,
  1059. NULL);
  1060. /************************************************************************/
  1061. /* Check that the handle returned by CreateFile is valid. For some */
  1062. /* peculiar reason it does return NULL if it fails - instead it returns */
  1063. /* -1 (INVALID_HANDLE_VALUE). */
  1064. /************************************************************************/
  1065. if (INVALID_HANDLE_VALUE == trchFileObjects[fileNum])
  1066. {
  1067. TRCDebugOutput(_T("Failed to open trace file.\n"));
  1068. rc = TRC_RC_CREATE_FILE_FAILED;
  1069. DC_QUIT;
  1070. }
  1071. /************************************************************************/
  1072. /* Now check whether the file existed before the call to CreateFile. */
  1073. /* If it did then GetLastError returns ERROR_ALREADY_EXISTS (even */
  1074. /* though the function has succeeded). */
  1075. /************************************************************************/
  1076. if (0 == GetLastError())
  1077. {
  1078. /********************************************************************/
  1079. /* If the file did not exist before the call, GetLastError returns */
  1080. /* zero. In this case we want to fill the file with spaces. */
  1081. /********************************************************************/
  1082. blankFile = TRUE;
  1083. /********************************************************************/
  1084. /* We have just created the file - so would expect to need to set */
  1085. /* the security info to allow all accesses. However, a) all works */
  1086. /* just fine without it, b) the attempt to set the security stuff */
  1087. /* fails if inserted here. So we'll just go along happily without. */
  1088. /********************************************************************/
  1089. }
  1090. #ifdef OS_WINCE
  1091. SetFilePointer(trchFileObjects[fileNum],
  1092. 0,
  1093. NULL,
  1094. FILE_END);
  1095. #else
  1096. /************************************************************************/
  1097. /* Make sure that the end of the file is correctly set. The file may */
  1098. /* be of any size when we open it, but we need it to be */
  1099. /* <trcpConfig->maxFileSize> bytes long. */
  1100. /************************************************************************/
  1101. SetFilePointer(trchFileObjects[fileNum],
  1102. trcpConfig->maxFileSize,
  1103. NULL,
  1104. FILE_BEGIN);
  1105. SetEndOfFile(trchFileObjects[fileNum]);
  1106. /************************************************************************/
  1107. /* Generate the file mapping object name. This is used in */
  1108. /* CreateFileMapping. */
  1109. /************************************************************************/
  1110. hr = StringCchPrintf(objectName,
  1111. SIZE_TCHARS(objectName),
  1112. TRC_TRACE_FILE_NAME _T("%hu"), fileNum);
  1113. if (FAILED(hr)) {
  1114. DC_QUIT;
  1115. }
  1116. /************************************************************************/
  1117. /* Now create the file mapping object. Again ignore security */
  1118. /* attributes (parameter 2) and set the high order 32 bits of the */
  1119. /* object size to 0 (see Win32 SDK for more information). */
  1120. /* */
  1121. /* Create the file mapping object using a NULL Dacl so it works for all */
  1122. /* contexts. */
  1123. /************************************************************************/
  1124. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1125. GetVersionEx(&ver);
  1126. if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  1127. /************************************************************************/
  1128. /* Get the SID for the Everyone group */
  1129. /************************************************************************/
  1130. if (!AllocateAndInitializeSid (
  1131. &sidEveryoneAuthority, // pIdentifierAuthority
  1132. 1, // count of subauthorities
  1133. SECURITY_WORLD_RID, // subauthority 0
  1134. 0, 0, 0, 0, 0, 0, 0, // subauthorities n
  1135. &psidEveryone)) { // pointer to pointer to SID
  1136. rc = TRC_RC_MAP_VIEW_FAILED;
  1137. OutputDebugString(_T("AllocateAndInitializeSid failed.\n"));
  1138. DC_QUIT;
  1139. }
  1140. /************************************************************************/
  1141. /* Allocate the Dacl */
  1142. /************************************************************************/
  1143. dwDaclLength = sizeof(ACL);
  1144. dwDaclLength += (sizeof(ACCESS_DENIED_ACE) - sizeof(DWORD)) +
  1145. GetLengthSid(psidEveryone);
  1146. dwDaclLength += (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
  1147. GetLengthSid(psidEveryone);
  1148. pDacl = (PACL)LocalAlloc(LMEM_FIXED, dwDaclLength);
  1149. if (pDacl == NULL) {
  1150. OutputDebugString(_T("Can't allocate Dacl.\n"));
  1151. rc = TRC_RC_MAP_VIEW_FAILED;
  1152. DC_QUIT;
  1153. }
  1154. /************************************************************************/
  1155. /* Initialize it. */
  1156. /************************************************************************/
  1157. if (!InitializeAcl(pDacl, dwDaclLength, ACL_REVISION)) {
  1158. rc = TRC_RC_MAP_VIEW_FAILED;
  1159. OutputDebugString(_T("InitializeAcl failed.\n"));
  1160. DC_QUIT;
  1161. }
  1162. /************************************************************************/
  1163. /* Allow all access */
  1164. /************************************************************************/
  1165. if (!AddAccessAllowedAce(
  1166. pDacl,
  1167. ACL_REVISION,
  1168. GENERIC_ALL,
  1169. psidEveryone)) {
  1170. rc = TRC_RC_MAP_VIEW_FAILED;
  1171. OutputDebugString(_T("AddAccessAllowedAce failed.\n"));
  1172. DC_QUIT;
  1173. }
  1174. /************************************************************************/
  1175. /* Block Write-DACL Access */
  1176. /************************************************************************/
  1177. if (!AddAccessDeniedAce(
  1178. pDacl,
  1179. ACL_REVISION,
  1180. WRITE_DAC,
  1181. psidEveryone)) {
  1182. rc = TRC_RC_MAP_VIEW_FAILED;
  1183. OutputDebugString(_T("AddAccessDeniedAceEx failed.\n"));
  1184. DC_QUIT;
  1185. }
  1186. /************************************************************************/
  1187. /* Create the File Mapping
  1188. /************************************************************************/
  1189. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  1190. SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE);
  1191. sa.lpSecurityDescriptor = &sd;
  1192. trchMappingObjects[fileNum] = CreateFileMapping(trchFileObjects[fileNum],
  1193. &sa,
  1194. PAGE_READWRITE,
  1195. 0,
  1196. trcpConfig->maxFileSize,
  1197. objectName);
  1198. }
  1199. else {
  1200. trchMappingObjects[fileNum] = CreateFileMapping(trchFileObjects[fileNum],
  1201. NULL,
  1202. PAGE_READWRITE,
  1203. 0,
  1204. trcpConfig->maxFileSize,
  1205. objectName);
  1206. }
  1207. /************************************************************************/
  1208. /* Check that we succeeded in creating the file mapping object. */
  1209. /* CreateFileMapping returns NULL if it fails. */
  1210. /************************************************************************/
  1211. if (NULL == trchMappingObjects[fileNum])
  1212. {
  1213. TRCDebugOutput(_T("Failed to map trace file.\n"));
  1214. rc = TRC_RC_CREATE_MAPPING_FAILED;
  1215. DC_QUIT;
  1216. }
  1217. /************************************************************************/
  1218. /* Now map a view of the file. Set the low and high order offsets to */
  1219. /* zero (parameters 3 and 4). */
  1220. /************************************************************************/
  1221. trcpFiles[fileNum] = (PDCTCHAR)MapViewOfFile(trchMappingObjects[fileNum],
  1222. FILE_MAP_ALL_ACCESS,
  1223. 0,
  1224. 0,
  1225. trcpConfig->maxFileSize);
  1226. /************************************************************************/
  1227. /* Check that we mapped a view of the file. */
  1228. /************************************************************************/
  1229. if (NULL == trcpFiles[fileNum])
  1230. {
  1231. TRCDebugOutput(_T("Failed to map view of trace file.\n"));
  1232. rc = TRC_RC_MAP_VIEW_FAILED;
  1233. DC_QUIT;
  1234. }
  1235. /************************************************************************/
  1236. /* Finally check to see if we need to blank this file. */
  1237. /************************************************************************/
  1238. if (blankFile)
  1239. {
  1240. TRCBlankFile(fileNum);
  1241. }
  1242. #endif
  1243. DC_EXIT_POINT:
  1244. /************************************************************************/
  1245. /* If the return code is non-zero then we need to perform some tidying */
  1246. /* up. */
  1247. /************************************************************************/
  1248. if (0 != rc)
  1249. {
  1250. #ifndef OS_WINCE
  1251. /********************************************************************/
  1252. /* Check whether we need to free the handle to the file mapping */
  1253. /* object. */
  1254. /********************************************************************/
  1255. if (NULL != trchMappingObjects[fileNum])
  1256. {
  1257. CloseHandle(trchMappingObjects[fileNum]);
  1258. trchMappingObjects[fileNum] = NULL;
  1259. }
  1260. #endif
  1261. /********************************************************************/
  1262. /* Check whether we need to free the handle to the file object. */
  1263. /********************************************************************/
  1264. if (NULL != trchFileObjects[fileNum])
  1265. {
  1266. CloseHandle(trchFileObjects[fileNum]);
  1267. trchFileObjects[fileNum] = NULL;
  1268. }
  1269. }
  1270. #ifndef OS_WINCE
  1271. if (pDacl) {
  1272. LocalFree(pDacl);
  1273. }
  1274. if (psidEveryone) {
  1275. FreeSid(psidEveryone);
  1276. }
  1277. #endif
  1278. return(rc);
  1279. } /* TRCOpenSingleFile */
  1280. /****************************************************************************/
  1281. /* FUNCTION: TRCOutputToFile(...) */
  1282. /* */
  1283. /* DESCRIPTION: */
  1284. /* ============ */
  1285. /* This function writes a string to the trace file. It is used to trace */
  1286. /* both normal trace lines and stack trace lines. */
  1287. /* */
  1288. /* PARAMETERS: */
  1289. /* =========== */
  1290. /* pText : a pointer to the trace text string. */
  1291. /* length : length of the string. */
  1292. /* traceLevel : the current trace level. */
  1293. /* */
  1294. /* RETURNS: */
  1295. /* ======== */
  1296. /* Nothing. */
  1297. /* */
  1298. /****************************************************************************/
  1299. DCVOID DCINTERNAL TRCOutputToFile(PDCTCHAR pText,
  1300. DCUINT length,
  1301. DCUINT traceLevel)
  1302. {
  1303. #ifndef OS_WINCE
  1304. PDCUINT8 pFilePos;
  1305. /************************************************************************/
  1306. /* Make sure we have a trace file with enough free space. */
  1307. /************************************************************************/
  1308. TRCMaybeSwapFile(length);
  1309. /************************************************************************/
  1310. /* We can now write out the trace line. */
  1311. /************************************************************************/
  1312. pFilePos = (PDCUINT8)trcpFiles[trcpSharedData->trcIndicator] +
  1313. trcpSharedData->trcOffset;
  1314. DC_MEMCPY(pFilePos, pText, length);
  1315. /************************************************************************/
  1316. /* Check if we should flush this line to disk immediately. If this is */
  1317. /* an error or higher level trace then flush to disk regardless. */
  1318. /************************************************************************/
  1319. if ((TRUE == TEST_FLAG(trcpConfig->flags, TRC_OPT_FLUSH_ON_TRACE)) ||
  1320. (traceLevel >= TRC_LEVEL_ERR))
  1321. {
  1322. FlushViewOfFile(pFilePos, length);
  1323. }
  1324. /************************************************************************/
  1325. /* Finally update the offset. */
  1326. /************************************************************************/
  1327. trcpSharedData->trcOffset += length;
  1328. #else
  1329. DWORD dwRet;
  1330. WriteFile(trchFileObjects[0], pText, length, &dwRet, NULL);
  1331. #endif
  1332. DC_EXIT_POINT:
  1333. return;
  1334. } /* TRCOutputToFile */
  1335. /****************************************************************************/
  1336. /* FUNCTION: TRCReadEntry(...) */
  1337. /* */
  1338. /* DESCRIPTION: */
  1339. /* ============ */
  1340. /* Read an entry from the given section of the registry. */
  1341. /* */
  1342. /* PARAMETERS: */
  1343. /* =========== */
  1344. /* topLevelKey : one of: */
  1345. /* - HKEY_CURRENT_USER */
  1346. /* - HKEY_LOCAL_MACHINE */
  1347. /* pSection : the section name to read from. The DC_REG_PREFIX */
  1348. /* string is prepended to give the full name. */
  1349. /* pEntry : the entry name to read. */
  1350. /* pBuffer : a buffer to read the entry to. */
  1351. /* bufferSize : the size of the buffer. */
  1352. /* expectedDataType : the type of data stored in the entry. */
  1353. /* */
  1354. /* RETURNS: */
  1355. /* ======== */
  1356. /* Nothing. */
  1357. /* */
  1358. /****************************************************************************/
  1359. DCUINT DCINTERNAL TRCReadEntry(HKEY topLevelKey,
  1360. PDCTCHAR pEntry,
  1361. PDCTCHAR pBuffer,
  1362. DCINT bufferSize,
  1363. DCINT32 expectedDataType)
  1364. {
  1365. LONG sysrc;
  1366. HKEY key;
  1367. DCINT32 dataType;
  1368. DCINT32 dataSize;
  1369. DCTCHAR subKey[TRC_MAX_SUBKEY];
  1370. DCBOOL keyOpen = FALSE;
  1371. DCUINT rc = 0;
  1372. HRESULT hr;
  1373. /************************************************************************/
  1374. /* Get a subkey for the value. */
  1375. /************************************************************************/
  1376. hr = StringCchCopy(subKey,
  1377. SIZE_TCHARS(subKey),
  1378. TRC_SUBKEY_NAME);
  1379. if (FAILED(hr)) {
  1380. DC_QUIT;
  1381. }
  1382. /************************************************************************/
  1383. /* Try to open the key. If the entry does not exist, RegOpenKeyEx will */
  1384. /* fail. */
  1385. /************************************************************************/
  1386. sysrc = RegOpenKeyEx(topLevelKey,
  1387. subKey,
  1388. 0, /* reserved */
  1389. KEY_ALL_ACCESS,
  1390. &key);
  1391. if (ERROR_SUCCESS != sysrc)
  1392. {
  1393. /********************************************************************/
  1394. /* Don't trace an error here since the subkey may not exist... */
  1395. /********************************************************************/
  1396. rc = TRC_RC_IO_ERROR;
  1397. DC_QUIT;
  1398. }
  1399. keyOpen = TRUE;
  1400. /************************************************************************/
  1401. /* We successfully opened the key so now try to read the value. Again */
  1402. /* it may not exist. */
  1403. /************************************************************************/
  1404. dataSize = (DCINT32)bufferSize;
  1405. sysrc = RegQueryValueEx(key,
  1406. pEntry,
  1407. 0, /* reserved */
  1408. (LPDWORD) &dataType,
  1409. (LPBYTE) pBuffer,
  1410. (LPDWORD) &dataSize);
  1411. if (sysrc != ERROR_SUCCESS)
  1412. {
  1413. rc = TRC_RC_IO_ERROR;
  1414. DC_QUIT;
  1415. }
  1416. /************************************************************************/
  1417. /* Check that the type is correct. Special case: allow REG_BINARY */
  1418. /* instead of REG_DWORD, as long as the length is 32 bits. */
  1419. /************************************************************************/
  1420. if ((dataType != expectedDataType) &&
  1421. ((dataType != REG_BINARY) ||
  1422. (expectedDataType != REG_DWORD) ||
  1423. (dataSize != 4)))
  1424. {
  1425. rc = TRC_RC_IO_ERROR;
  1426. DC_QUIT;
  1427. }
  1428. DC_EXIT_POINT:
  1429. /************************************************************************/
  1430. /* Close the key (if required). */
  1431. /************************************************************************/
  1432. if (keyOpen)
  1433. {
  1434. sysrc = RegCloseKey(key);
  1435. if (ERROR_SUCCESS != sysrc)
  1436. {
  1437. TRCDebugOutput(_T("Failed to close key.\n"));
  1438. }
  1439. }
  1440. return(rc);
  1441. } /* TRCReadEntry */
  1442. /****************************************************************************/
  1443. /* FUNCTION: TRCStackTrace(...) */
  1444. /* */
  1445. /* DESCRIPTION: */
  1446. /* ============ */
  1447. /* */
  1448. /* PARAMETERS: */
  1449. /* =========== */
  1450. /* traceLevel : the current trace level which is used to determine */
  1451. /* whether this line should be flushed to disk */
  1452. /* immediately. */
  1453. /* */
  1454. /* RETURNS: */
  1455. /* ======== */
  1456. /* Nothing. */
  1457. /* */
  1458. /****************************************************************************/
  1459. DCVOID DCINTERNAL TRCStackTrace(DCUINT traceLevel)
  1460. {
  1461. DC_IGNORE_PARAMETER(traceLevel);
  1462. #ifdef DO_STACK_TRACE
  1463. HANDLE hProcess;
  1464. HANDLE hThread;
  1465. DCBOOL sysrc;
  1466. STACKFRAME stackFrame;
  1467. DWORD machineType;
  1468. IMAGEHLP_MODULE moduleInfo;
  1469. DCINT i;
  1470. DCTCHAR formatString[TRC_FRMT_BUFFER_SIZE];
  1471. CONTEXT threadContext;
  1472. CHAR symBuffer[sizeof(IMAGEHLP_SYMBOL)+TRC_MAX_SYMNAME_SIZE];
  1473. PIMAGEHLP_SYMBOL pSymbol;
  1474. PCHAR pFuncName;
  1475. DWORD displacement = 0;
  1476. DCBOOL foundTrace = FALSE;
  1477. /************************************************************************/
  1478. /* First of all ensure that stack tracing is enabled - if it is not */
  1479. /* then just return. */
  1480. /************************************************************************/
  1481. /************************************************************************/
  1482. /* The stack trace code doesn't work for Alpha so don't bother trying. */
  1483. /************************************************************************/
  1484. #ifndef _M_ALPHA
  1485. if (!TEST_FLAG(trcpConfig->flags, TRC_OPT_STACK_TRACING))
  1486. #endif
  1487. {
  1488. DC_QUIT;
  1489. }
  1490. /************************************************************************/
  1491. /* Set <pSymbol> to point to the symbol buffer. */
  1492. /************************************************************************/
  1493. pSymbol = (PIMAGEHLP_SYMBOL) symBuffer;
  1494. /************************************************************************/
  1495. /* Zero memory structures. */
  1496. /************************************************************************/
  1497. ZeroMemory(&stackFrame, sizeof(stackFrame));
  1498. ZeroMemory(pSymbol, sizeof(IMAGEHLP_SYMBOL));
  1499. ZeroMemory(&threadContext, sizeof(CONTEXT));
  1500. /************************************************************************/
  1501. /* Initialize the symbol buffer. */
  1502. /************************************************************************/
  1503. pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  1504. pSymbol->MaxNameLength = 1024;
  1505. /************************************************************************/
  1506. /* Get handles to the current process and thread. */
  1507. /************************************************************************/
  1508. hProcess = GetCurrentProcess();
  1509. hThread = GetCurrentThread();
  1510. /************************************************************************/
  1511. /* We need to get the values of the base pointer, stack pointer and the */
  1512. /* instruction pointer. We can use <GetContextThread> to return this */
  1513. /* information - but first of all we need to set the <ContextFlags> */
  1514. /* member of the <threadContext> struture to return the control */
  1515. /* registers. */
  1516. /************************************************************************/
  1517. threadContext.ContextFlags = CONTEXT_CONTROL;
  1518. /************************************************************************/
  1519. /* Now attempt to get the thread context. */
  1520. /************************************************************************/
  1521. if (!GetThreadContext(hThread, &threadContext))
  1522. {
  1523. /********************************************************************/
  1524. /* If <GetThreadContext> failed then there is not a lot we can do */
  1525. /* so just quit. */
  1526. /********************************************************************/
  1527. TRCInternalError(_T("GetThreadContext failed.\n"));
  1528. DC_QUIT;
  1529. }
  1530. /************************************************************************/
  1531. /* Store the instruction pointer in the <stackFrame> structure. */
  1532. /************************************************************************/
  1533. stackFrame.AddrPC.Mode = AddrModeFlat;
  1534. /************************************************************************/
  1535. /* Processor dependant section. We set the image file type here and if */
  1536. /* we are running on Intel hardware we also store the stack pointer and */
  1537. /* base pointer. */
  1538. /************************************************************************/
  1539. #if defined(_M_IX86)
  1540. machineType = IMAGE_FILE_MACHINE_I386;
  1541. stackFrame.AddrPC.Offset = threadContext.Eip;
  1542. stackFrame.AddrFrame.Offset = threadContext.Ebp;
  1543. stackFrame.AddrFrame.Mode = AddrModeFlat;
  1544. stackFrame.AddrStack.Offset = threadContext.Esp;
  1545. stackFrame.AddrStack.Mode = AddrModeFlat;
  1546. #elif defined (_M_MRX000)
  1547. machineType = IMAGE_FILE_MACHINE_R4000;
  1548. #elif defined (_M_ALPHA)
  1549. machineType = IMAGE_FILE_MACHINE_ALPHA;
  1550. #elif defined (_M_PPC)
  1551. machineType = IMAGE_FILE_MACHINE_POWERPC;
  1552. #else
  1553. #error("Unknown machine type.");
  1554. #endif
  1555. /************************************************************************/
  1556. /* Now run down the stack. */
  1557. /************************************************************************/
  1558. for (i = 1; i < TRC_MAX_SIZE_STACK_TRACE; i++)
  1559. {
  1560. /********************************************************************/
  1561. /* Call <StackWalk> to start walking the stack. */
  1562. /********************************************************************/
  1563. sysrc = StackWalk(machineType,
  1564. hProcess,
  1565. hThread,
  1566. &stackFrame,
  1567. &threadContext,
  1568. NULL,
  1569. SymFunctionTableAccess,
  1570. SymGetModuleBase,
  1571. NULL);
  1572. /********************************************************************/
  1573. /* Check the return code. */
  1574. /********************************************************************/
  1575. if (FALSE == sysrc)
  1576. {
  1577. /****************************************************************/
  1578. /* Don't trace anything here as we enter here when we reach */
  1579. /* the end of the stack. */
  1580. /****************************************************************/
  1581. DC_QUIT;
  1582. }
  1583. /********************************************************************/
  1584. /* Get the module name. */
  1585. /********************************************************************/
  1586. sysrc = SymGetModuleInfo(hProcess,
  1587. stackFrame.AddrPC.Offset,
  1588. &moduleInfo);
  1589. /********************************************************************/
  1590. /* Check the return code. */
  1591. /********************************************************************/
  1592. if (FALSE == sysrc)
  1593. {
  1594. /****************************************************************/
  1595. /* Don't trace anything as we enter here when we reach the end */
  1596. /* of the stack. */
  1597. /****************************************************************/
  1598. DC_QUIT;
  1599. }
  1600. /********************************************************************/
  1601. /* When we start we are somewhere in the midst of */
  1602. /* <GetThreadContext>. Since we're only interested in the stack */
  1603. /* above the trace module then we need to skip everything until we */
  1604. /* pass the trace module. */
  1605. /* */
  1606. /* Look for the trace module name. */
  1607. /********************************************************************/
  1608. if (DC_TSTRCMPI(trcpSharedData->trcpModuleFileName,
  1609. moduleInfo.ModuleName) == 0)
  1610. {
  1611. /****************************************************************/
  1612. /* They match so set the <foundTrace> flag and the continue. */
  1613. /****************************************************************/
  1614. foundTrace = TRUE;
  1615. continue;
  1616. }
  1617. /********************************************************************/
  1618. /* We've not found the trace module yet so just continue. */
  1619. /********************************************************************/
  1620. if (!foundTrace)
  1621. {
  1622. continue;
  1623. }
  1624. /********************************************************************/
  1625. /* Now get the symbol name. */
  1626. /********************************************************************/
  1627. sysrc = SymGetSymFromAddr(hProcess,
  1628. stackFrame.AddrPC.Offset,
  1629. &displacement,
  1630. pSymbol);
  1631. /********************************************************************/
  1632. /* Check the return code. */
  1633. /********************************************************************/
  1634. if (sysrc)
  1635. {
  1636. /****************************************************************/
  1637. /* We've found some symbols so use them. */
  1638. /****************************************************************/
  1639. pFuncName = pSymbol->Name;
  1640. }
  1641. else
  1642. {
  1643. /****************************************************************/
  1644. /* No symbols available. */
  1645. /****************************************************************/
  1646. pFuncName = _T("<nosymbols>");
  1647. }
  1648. /********************************************************************/
  1649. /* Finally format the string. */
  1650. /********************************************************************/
  1651. hr = StringCchPrintf(
  1652. formatString,
  1653. SIZE_TCHARS(formatString),
  1654. _T(" ") TRC_MODL_FMT _T("!") TRC_FUNC_FMT _T(" : ") TRC_STCK_FMT_T("\r\n"),
  1655. moduleInfo.ModuleName,
  1656. trcpConfig->funcNameLength,
  1657. trcpConfig->funcNameLength,
  1658. pFuncName,
  1659. displacement,
  1660. stackFrame.AddrFrame.Offset,
  1661. stackFrame.AddrReturn.Offset,
  1662. stackFrame.Params[0],
  1663. stackFrame.Params[1],
  1664. stackFrame.Params[2],
  1665. stackFrame.Params[3]
  1666. );
  1667. if (SUCCEEDED(hr)) {
  1668. /********************************************************************/
  1669. /* Output this line of the <formatString>. */
  1670. /********************************************************************/
  1671. TRCOutput(formatString, DC_TSTRLEN(formatString), traceLevel);
  1672. }
  1673. }
  1674. DC_EXIT_POINT:
  1675. return;
  1676. #endif /* DO_STACK_TRACE */
  1677. } /* TRCStackTrace */
  1678. /****************************************************************************/
  1679. /* FUNCTION: TRCSymbolsLoad(...) */
  1680. /* */
  1681. /* DESCRIPTION: */
  1682. /* ============ */
  1683. /* Function to load symbolic debugging information. This function should */
  1684. /* only be called if the trace mutex has been obtained. */
  1685. /* */
  1686. /* PARAMETERS: */
  1687. /* =========== */
  1688. /* None. */
  1689. /* */
  1690. /* RETURNS: */
  1691. /* ======== */
  1692. /* 0 : success. */
  1693. /* TRC_SYMBOL_LOAD_FAILED : failed to load symbols. */
  1694. /* */
  1695. /****************************************************************************/
  1696. DCUINT DCINTERNAL TRCSymbolsLoad(DCVOID)
  1697. {
  1698. DCUINT rc = 0;
  1699. HANDLE hProcess;
  1700. #ifdef DO_STACK_TRACE
  1701. DWORD options;
  1702. #endif
  1703. /************************************************************************/
  1704. /* Get the current process handle. */
  1705. /************************************************************************/
  1706. hProcess = GetCurrentProcess();
  1707. /************************************************************************/
  1708. /* We're about to load symbols - so trace a line out. */
  1709. /************************************************************************/
  1710. TRCInternalTrace(TRC_SYMBOLS_LOADING_NOTIFY);
  1711. #ifdef DO_STACK_TRACE
  1712. /************************************************************************/
  1713. /* Now set the deferred symbol load option. For some peculiar reason */
  1714. /* this is not set by default. */
  1715. /************************************************************************/
  1716. options = SymGetOptions();
  1717. SymSetOptions(options | SYMOPT_DEFERRED_LOADS);
  1718. /************************************************************************/
  1719. /* Initialize the symbol handler for this process. By setting param 2 */
  1720. /* to NULL the search path for the symbols is as follows: */
  1721. /* */
  1722. /* - Current directory */
  1723. /* - Env variable _NT_SYMBOL_PATH */
  1724. /* - Env variable _NT_ALTERNATE_SYMBOL_PATH */
  1725. /* - Env variable SYSTEMROOT */
  1726. /* */
  1727. /* By setting the third parameter to TRUE we tell IMAGEHLP to enumerate */
  1728. /* the loaded modules for this process (this effectively calls */
  1729. /* <SymLoadModule> for each module). */
  1730. /************************************************************************/
  1731. /************************************************************************/
  1732. /* LAURABU: */
  1733. /* SymInitialize returns FALSE on Win95. Moreover, it makes no sense */
  1734. /* to fail to start up on either NT or Win95 just because this dll */
  1735. /* couldn't load debug symbols. Therefore don't fail. */
  1736. /************************************************************************/
  1737. if (!(SymInitialize(hProcess, NULL, TRUE)))
  1738. {
  1739. #ifdef DC_OMIT
  1740. rc = TRC_RC_SYMBOL_LOAD_FAILED;
  1741. #endif
  1742. TRCDebugOutput(_T("SymInitialize failed.\n"));
  1743. #ifdef DC_OMIT
  1744. DC_QUIT;
  1745. #endif
  1746. }
  1747. #endif
  1748. /************************************************************************/
  1749. /* Set the flag to indicate the symbols have been loaded. */
  1750. /************************************************************************/
  1751. SET_FLAG(trcProcessStatus, TRC_STATUS_SYMBOLS_LOADED);
  1752. /************************************************************************/
  1753. /* Write a status line. The assumption here is that this is done under */
  1754. /* the mutex. */
  1755. /************************************************************************/
  1756. TRCInternalTrace(TRC_SYMBOLS_LOADED_NOTIFY);
  1757. DC_EXIT_POINT:
  1758. return(rc);
  1759. } /* TRCSymbolsLoad */
  1760. /****************************************************************************/
  1761. /* FUNCTION: TRCSymbolsUnload(...) */
  1762. /* */
  1763. /* DESCRIPTION: */
  1764. /* ============ */
  1765. /* */
  1766. /* PARAMETERS: */
  1767. /* =========== */
  1768. /* None. */
  1769. /* */
  1770. /* RETURNS: */
  1771. /* ======== */
  1772. /* TRUE if successful and FALSE otherwise. */
  1773. /* */
  1774. /****************************************************************************/
  1775. DCBOOL DCINTERNAL TRCSymbolsUnload(DCVOID)
  1776. {
  1777. DCBOOL rc = TRUE;
  1778. #ifdef DO_STACK_TRACE
  1779. HANDLE hProcess;
  1780. /************************************************************************/
  1781. /* Get the current process handle. */
  1782. /************************************************************************/
  1783. hProcess = GetCurrentProcess();
  1784. /************************************************************************/
  1785. /* Cleanup the symbols. */
  1786. /************************************************************************/
  1787. rc = SymCleanup(hProcess);
  1788. /************************************************************************/
  1789. /* Check the return code. */
  1790. /************************************************************************/
  1791. if (FALSE == rc)
  1792. {
  1793. TRCDebugOutput(_T("SymCleanup failed.\n"));
  1794. DC_QUIT;
  1795. }
  1796. #endif
  1797. /************************************************************************/
  1798. /* Clear the symbols loaded flag. */
  1799. /************************************************************************/
  1800. CLEAR_FLAG(trcProcessStatus, TRC_STATUS_SYMBOLS_LOADED);
  1801. /************************************************************************/
  1802. /* Write a status line to the trace file. The assumption here is that */
  1803. /* this is done under the mutex. */
  1804. /************************************************************************/
  1805. TRCInternalTrace(TRC_SYMBOLS_UNLOAD_NOTIFY);
  1806. DC_EXIT_POINT:
  1807. return(rc);
  1808. } /* TRCSymbolsLoad */
  1809. /****************************************************************************/
  1810. /* FUNCTION: TRCWriteEntry(...) */
  1811. /* */
  1812. /* DESCRIPTION: */
  1813. /* ============ */
  1814. /* Write an entry to the given section of the registry. */
  1815. /* */
  1816. /* PARAMETERS: */
  1817. /* =========== */
  1818. /* topLevelKey : one of: */
  1819. /* - HKEY_CURRENT_USER */
  1820. /* - HKEY_LOCAL_MACHINE */
  1821. /* pEntry : the entry name to write. */
  1822. /* pData : a pointer to the data to be written. */
  1823. /* dataSize : the size of the data to be written. For strings, this */
  1824. /* should include the NULL terminator. */
  1825. /* dataType : the type of the data to be written. */
  1826. /* */
  1827. /* RETURNS: */
  1828. /* ======== */
  1829. /* 0 : success */
  1830. /* TRC_RC_IO_ERROR : I/O error. */
  1831. /* */
  1832. /****************************************************************************/
  1833. DCUINT DCINTERNAL TRCWriteEntry(HKEY topLevelKey,
  1834. PDCTCHAR pEntry,
  1835. PDCTCHAR pData,
  1836. DCINT dataSize,
  1837. DCINT32 dataType)
  1838. {
  1839. LONG sysrc;
  1840. HKEY key;
  1841. DCTCHAR subKey[TRC_MAX_SUBKEY];
  1842. DWORD disposition;
  1843. DCBOOL keyOpen = FALSE;
  1844. DCUINT rc = 0;
  1845. HRESULT hr;
  1846. /************************************************************************/
  1847. /* Get a subkey for the value. */
  1848. /************************************************************************/
  1849. hr = StringCchCopy(subKey,
  1850. SIZE_TCHARS(subKey),
  1851. TRC_SUBKEY_NAME);
  1852. if (FAILED(hr)) {
  1853. DC_QUIT;
  1854. }
  1855. /************************************************************************/
  1856. /* Try to create the key. If the entry already exists, RegCreateKeyEx */
  1857. /* will open the existing entry. */
  1858. /************************************************************************/
  1859. sysrc = RegCreateKeyEx(topLevelKey,
  1860. subKey,
  1861. 0, /* reserved */
  1862. NULL, /* class */
  1863. REG_OPTION_NON_VOLATILE,
  1864. KEY_ALL_ACCESS,
  1865. NULL, /* security attributes */
  1866. &key,
  1867. &disposition);
  1868. if (ERROR_SUCCESS != sysrc)
  1869. {
  1870. DCTCHAR output[12];
  1871. TRCDebugOutput(_T("Failed to create key failed with error "));
  1872. hr = StringCchPrintf(output, SIZE_TCHARS(output),
  1873. _T("%#lx"), GetLastError());
  1874. if (SUCCEEDED(hr)) {
  1875. TRCDebugOutput(output);
  1876. }
  1877. DC_QUIT;
  1878. }
  1879. keyOpen = TRUE;
  1880. /************************************************************************/
  1881. /* We've got the key, so set the value. */
  1882. /************************************************************************/
  1883. sysrc = RegSetValueEx(key,
  1884. pEntry,
  1885. 0, /* reserved */
  1886. dataType,
  1887. (LPBYTE) pData,
  1888. (DCINT32) dataSize);
  1889. if (ERROR_SUCCESS != sysrc)
  1890. {
  1891. DCTCHAR output[12];
  1892. TRCDebugOutput(_T("Failed to set value failed with error "));
  1893. hr = StringCchPrintf(output, SIZE_TCHARS(output),
  1894. _T("%#lx"), GetLastError());
  1895. if (SUCCEEDED(hr)) {
  1896. TRCDebugOutput(output);
  1897. }
  1898. DC_QUIT;
  1899. }
  1900. DC_EXIT_POINT:
  1901. /************************************************************************/
  1902. /* Close the key (if required) */
  1903. /************************************************************************/
  1904. if (keyOpen)
  1905. {
  1906. sysrc = RegCloseKey(key);
  1907. if (ERROR_SUCCESS != sysrc)
  1908. {
  1909. TRCDebugOutput(_T("Failed to close key.\n"));
  1910. }
  1911. }
  1912. return(rc);
  1913. } /* TRCWriteEntry */
  1914. /****************************************************************************/
  1915. /* We have our own implementation of DebugBreak that on NT checks if a */
  1916. /* debugger is present first before calling DebugBreak(). Otherwise the */
  1917. /* app will just get terminated due to an unhandled exception. */
  1918. /****************************************************************************/
  1919. typedef BOOL (WINAPI * PFN_ISDEBUGGERPRESENT)(void);
  1920. DCVOID DCINTERNAL TRCDebugBreak(DCVOID)
  1921. {
  1922. static PFN_ISDEBUGGERPRESENT s_pfnIsDebuggerPresent = NULL;
  1923. static BOOL s_fHaveWeTriedToFindIt = FALSE;
  1924. if (! s_pfnIsDebuggerPresent)
  1925. {
  1926. if (!InterlockedExchange((long *)&s_fHaveWeTriedToFindIt, TRUE))
  1927. {
  1928. /****************************************************************/
  1929. /* Try to get the proc address of "IsDebuggerPresent". Note we */
  1930. /* can just write into this variable without Interlocked stuff */
  1931. /* since dwords get written to and read from atomically. */
  1932. /****************************************************************/
  1933. #ifndef OS_WINCE
  1934. s_pfnIsDebuggerPresent = (PFN_ISDEBUGGERPRESENT)
  1935. GetProcAddress(GetModuleHandle(_T("kernel32.dll")),
  1936. "IsDebuggerPresent");
  1937. #else // OS_WINCE
  1938. HMODULE hmod;
  1939. hmod = LoadLibrary(_T("kernel32.dll"));
  1940. s_pfnIsDebuggerPresent = (PFN_ISDEBUGGERPRESENT)
  1941. GetProcAddress(hmod,
  1942. _T("IsDebuggerPresent"));
  1943. FreeLibrary(hmod);
  1944. #endif
  1945. }
  1946. }
  1947. /************************************************************************/
  1948. /* If this api doesn't exist, we are on Win95, so go ahead and call */
  1949. /* DebugBreak(). If it does, we are on NT 4, so find out if a debugger */
  1950. /* is around. If a debugger isn't there, then don't break for now */
  1951. /* since we don't have debuggers attached to most of our NT machines */
  1952. /* yet. */
  1953. /************************************************************************/
  1954. if (!s_pfnIsDebuggerPresent || (s_pfnIsDebuggerPresent()))
  1955. DebugBreak();
  1956. }