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.

1072 lines
28 KiB

  1. /*******************************************************************************
  2. *
  3. * TRACE.C
  4. * This module implements the trace functions
  5. *
  6. * Copyright 1998, Microsoft.
  7. *
  8. *
  9. ******************************************************************************/
  10. /*
  11. * Includes
  12. */
  13. #include <precomp.h>
  14. #pragma hdrstop
  15. #include <ctxdd.h>
  16. /*=============================================================================
  17. == External Functions Defined
  18. =============================================================================*/
  19. NTSTATUS IcaStartStopTrace( PICA_TRACE_INFO, PICA_TRACE );
  20. VOID _cdecl IcaSystemTrace( ULONG, ULONG, CHAR *, ... );
  21. VOID IcaSystemTraceBuffer( ULONG, ULONG, PVOID, ULONG );
  22. VOID _cdecl IcaStackTrace( PSDCONTEXT, ULONG, ULONG, CHAR *, ... );
  23. VOID IcaStackTraceBuffer( PSDCONTEXT, ULONG, ULONG, PVOID, ULONG );
  24. VOID IcaTraceFormat( PICA_TRACE_INFO, ULONG, ULONG, CHAR * );
  25. VOID _cdecl _IcaTrace( PICA_CONNECTION, ULONG, ULONG, CHAR *, ... );
  26. VOID _cdecl _IcaStackTrace( PICA_STACK, ULONG, ULONG, CHAR *, ... );
  27. VOID _IcaStackTraceBuffer( PICA_STACK, ULONG, ULONG, PVOID, ULONG );
  28. VOID _cdecl _IcaChannelTrace( PICA_CHANNEL, ULONG, ULONG, CHAR *, ... );
  29. /*=============================================================================
  30. == Internal functions
  31. =============================================================================*/
  32. NTSTATUS _IcaOpenTraceFile( PICA_TRACE_INFO, PWCHAR );
  33. VOID _IcaCloseTraceFile( PICA_TRACE_INFO );
  34. VOID _IcaTraceWrite( PICA_TRACE_INFO, PVOID );
  35. VOID _IcaFlushDeferredTrace( PICA_TRACE_INFO );
  36. int _FormatTime( CHAR *, ULONG );
  37. int _FormatThreadId( CHAR *, ULONG );
  38. VOID _WriteHexData( PICA_TRACE_INFO, PVOID, ULONG );
  39. /*=============================================================================
  40. == Global variables
  41. =============================================================================*/
  42. /*
  43. * Trace info
  44. */
  45. ICA_TRACE_INFO G_TraceInfo = { 0, 0, FALSE, FALSE, NULL, NULL, NULL };
  46. /*******************************************************************************
  47. *
  48. * IcaStartStopTrace
  49. *
  50. * Start/stop tracing
  51. *
  52. * ENTRY:
  53. * pTraceInfo (input)
  54. * pointer to ICA_TRACE_INFO struct
  55. * pTrace (input)
  56. * pointer to ICA_TRACE (IOCTL) trace settings
  57. *
  58. * EXIT:
  59. * STATUS_SUCCESS - no error
  60. *
  61. ******************************************************************************/
  62. NTSTATUS
  63. IcaStartStopTrace(
  64. IN PICA_TRACE_INFO pTraceInfo,
  65. IN PICA_TRACE pTrace
  66. )
  67. {
  68. NTSTATUS Status;
  69. /*
  70. * If a trace file was specified,
  71. * then open it and save a pointer to the file object.
  72. */
  73. if ( pTrace->TraceFile[0] ) {
  74. /*
  75. * Force a null termination for file name.
  76. */
  77. pTrace->TraceFile[255] = (WCHAR)0;
  78. Status = _IcaOpenTraceFile( pTraceInfo, pTrace->TraceFile );
  79. if ( !NT_SUCCESS( Status ) )
  80. return( Status );
  81. /*
  82. * If no trace file specified, then close any existing trace file
  83. */
  84. } else if ( pTraceInfo->pTraceFileName ) {
  85. _IcaCloseTraceFile( pTraceInfo );
  86. }
  87. /*
  88. * Set trace flags
  89. */
  90. pTraceInfo->fTraceDebugger = pTrace->fDebugger;
  91. pTraceInfo->fTraceTimestamp = pTrace->fTimestamp;
  92. pTraceInfo->TraceClass = pTrace->TraceClass;
  93. pTraceInfo->TraceEnable = pTrace->TraceEnable;
  94. return( STATUS_SUCCESS );
  95. }
  96. /*******************************************************************************
  97. *
  98. * IcaSystemTrace
  99. *
  100. * This routine conditional writes a trace record to the system trace file
  101. *
  102. * ENTRY:
  103. * TraceClass (input)
  104. * trace class bit mask
  105. * TraceEnable (input)
  106. * trace type bit mask
  107. * Format (input)
  108. * format string
  109. * ... (input)
  110. * enough arguments to satisfy format string
  111. *
  112. * EXIT:
  113. * nothing
  114. *
  115. ******************************************************************************/
  116. VOID _cdecl
  117. IcaSystemTrace( IN ULONG TraceClass,
  118. IN ULONG TraceEnable,
  119. IN CHAR * Format,
  120. IN ... )
  121. {
  122. va_list arg_marker;
  123. char Buffer[256];
  124. va_start( arg_marker, Format );
  125. /*
  126. * Check if this trace record should be output
  127. */
  128. if ( !(TraceClass & G_TraceInfo.TraceClass) || !(TraceEnable & G_TraceInfo.TraceEnable) )
  129. return;
  130. /*
  131. * Format trace data
  132. */
  133. _vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
  134. Buffer[sizeof(Buffer) -1] = '\0';
  135. /*
  136. * Write trace data
  137. */
  138. IcaTraceFormat( &G_TraceInfo, TraceClass, TraceEnable, Buffer );
  139. }
  140. /*******************************************************************************
  141. *
  142. * IcaSystemTraceBuffer
  143. *
  144. * This routine conditional writes a data buffer to the system trace file
  145. *
  146. * ENTRY:
  147. * TraceClass (input)
  148. * trace class bit mask
  149. * TraceEnable (input)
  150. * trace type bit mask
  151. * pBuffer (input)
  152. * pointer to data buffer
  153. * ByteCount (input)
  154. * length of buffer
  155. *
  156. * EXIT:
  157. * nothing
  158. *
  159. ******************************************************************************/
  160. VOID
  161. IcaSystemTraceBuffer( IN ULONG TraceClass,
  162. IN ULONG TraceEnable,
  163. IN PVOID pBuffer,
  164. IN ULONG ByteCount )
  165. {
  166. /*
  167. * Check if this trace record should be output
  168. */
  169. if ( !(TraceClass & G_TraceInfo.TraceClass) ||
  170. !(TraceEnable & G_TraceInfo.TraceEnable) )
  171. return;
  172. /*
  173. * Write trace data
  174. */
  175. _WriteHexData( &G_TraceInfo, pBuffer, ByteCount );
  176. }
  177. /*******************************************************************************
  178. *
  179. * IcaStackTrace
  180. *
  181. * This routine conditional writes a trace record depending on the trace mask
  182. *
  183. * ENTRY:
  184. * pContext (input)
  185. * pointer to stack driver context
  186. * TraceClass (input)
  187. * trace class bit mask
  188. * TraceEnable (input)
  189. * trace type bit mask
  190. * Format (input)
  191. * format string
  192. * ... (input)
  193. * enough arguments to satisfy format string
  194. *
  195. * EXIT:
  196. * nothing
  197. *
  198. ******************************************************************************/
  199. VOID _cdecl
  200. IcaStackTrace( IN PSDCONTEXT pContext,
  201. IN ULONG TraceClass,
  202. IN ULONG TraceEnable,
  203. IN CHAR * Format,
  204. IN ... )
  205. {
  206. va_list arg_marker;
  207. char Buffer[256];
  208. PICA_STACK pStack;
  209. PICA_CONNECTION pConnect;
  210. PICA_TRACE_INFO pTraceInfo;
  211. va_start( arg_marker, Format );
  212. /*
  213. * Use SD passed context to get the STACK object pointer.
  214. */
  215. pStack = (CONTAINING_RECORD( pContext, SDLINK, SdContext ))->pStack;
  216. pConnect = IcaGetConnectionForStack( pStack );
  217. /*
  218. * Check if this trace record should be output
  219. */
  220. pTraceInfo = &pConnect->TraceInfo;
  221. if ( !(TraceClass & pTraceInfo->TraceClass) ||
  222. !(TraceEnable & pTraceInfo->TraceEnable) )
  223. return;
  224. /*
  225. * Format trace data
  226. */
  227. _vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
  228. Buffer[sizeof(Buffer) -1] = '\0';
  229. /*
  230. * Write trace data
  231. */
  232. IcaTraceFormat( pTraceInfo, TraceClass, TraceEnable, Buffer );
  233. }
  234. /*******************************************************************************
  235. *
  236. * IcaStackTraceBuffer
  237. *
  238. * This routine conditional writes a data buffer to the trace file
  239. *
  240. * ENTRY:
  241. * pContext (input)
  242. * pointer to stack driver context
  243. * TraceClass (input)
  244. * trace class bit mask
  245. * TraceEnable (input)
  246. * trace type bit mask
  247. * pBuffer (input)
  248. * pointer to data buffer
  249. * ByteCount (input)
  250. * length of buffer
  251. *
  252. * EXIT:
  253. * nothing
  254. *
  255. ******************************************************************************/
  256. VOID
  257. IcaStackTraceBuffer( IN PSDCONTEXT pContext,
  258. IN ULONG TraceClass,
  259. IN ULONG TraceEnable,
  260. IN PVOID pBuffer,
  261. IN ULONG ByteCount )
  262. {
  263. PICA_TRACE_INFO pTraceInfo;
  264. PICA_STACK pStack;
  265. PICA_CONNECTION pConnect;
  266. /*
  267. * Use SD passed context to get the STACK object pointer.
  268. */
  269. pStack = (CONTAINING_RECORD( pContext, SDLINK, SdContext ))->pStack;
  270. pConnect = IcaGetConnectionForStack( pStack );
  271. /*
  272. * Check if this trace record should be output
  273. */
  274. pTraceInfo = &pConnect->TraceInfo;
  275. if ( !(TraceClass & pTraceInfo->TraceClass) ||
  276. !(TraceEnable & pTraceInfo->TraceEnable) )
  277. return;
  278. /*
  279. * Write trace data
  280. */
  281. _WriteHexData( pTraceInfo, pBuffer, ByteCount );
  282. }
  283. /*******************************************************************************
  284. *
  285. * IcaTraceFormat
  286. *
  287. * This routine conditional writes trace data depending on the trace mask
  288. *
  289. * ENTRY:
  290. * pTraceInfo (input)
  291. * pointer to ICA_TRACE_INFO struct
  292. * TraceClass (input)
  293. * trace class bit mask
  294. * TraceEnable (input)
  295. * trace type bit mask
  296. * pData (input)
  297. * pointer to null terminated trace data
  298. *
  299. * EXIT:
  300. * nothing
  301. *
  302. ******************************************************************************/
  303. VOID
  304. IcaTraceFormat( IN PICA_TRACE_INFO pTraceInfo,
  305. IN ULONG TraceClass,
  306. IN ULONG TraceEnable,
  307. IN CHAR * pData )
  308. {
  309. char Buffer[256];
  310. char * pBuf;
  311. int len = 0;
  312. int i;
  313. /*
  314. * Check if this trace record should be output
  315. */
  316. if ( !(TraceClass & pTraceInfo->TraceClass) || !(TraceEnable & pTraceInfo->TraceEnable) )
  317. return;
  318. pBuf = Buffer;
  319. /*
  320. * Append time stamp
  321. */
  322. if ( pTraceInfo->fTraceTimestamp ) {
  323. len = _FormatTime( pBuf, sizeof(Buffer) );
  324. pBuf += len;
  325. }
  326. /*
  327. * Append thread id
  328. */
  329. i = _FormatThreadId( pBuf, sizeof(Buffer) - len );
  330. len += i;
  331. pBuf += i;
  332. /*
  333. * Append trace data
  334. */
  335. _snprintf( pBuf, sizeof(Buffer) - len, pData );
  336. /*
  337. * Write trace data
  338. */
  339. _IcaTraceWrite( pTraceInfo, Buffer );
  340. }
  341. /*******************************************************************************
  342. *
  343. * _IcaTrace
  344. *
  345. * Write a trace record to the winstation trace file
  346. *
  347. * ENTRY:
  348. * pConnect (input)
  349. * pointer to connection structure
  350. * TraceClass (input)
  351. * trace class bit mask
  352. * TraceEnable (input)
  353. * trace type bit mask
  354. * Format (input)
  355. * format string
  356. * ... (input)
  357. * enough arguments to satisfy format string
  358. *
  359. * EXIT:
  360. * nothing
  361. *
  362. ******************************************************************************/
  363. VOID _cdecl
  364. _IcaTrace( IN PICA_CONNECTION pConnect,
  365. IN ULONG TraceClass,
  366. IN ULONG TraceEnable,
  367. IN CHAR * Format,
  368. IN ... )
  369. {
  370. va_list arg_marker;
  371. char Buffer[256];
  372. PICA_TRACE_INFO pTraceInfo;
  373. ASSERT( pConnect->Header.Type == IcaType_Connection );
  374. va_start( arg_marker, Format );
  375. pTraceInfo = &pConnect->TraceInfo;
  376. /*
  377. * Check if this trace record should be output
  378. */
  379. if ( !(TraceClass & pTraceInfo->TraceClass) || !(TraceEnable & pTraceInfo->TraceEnable) )
  380. return;
  381. /*
  382. * Format trace data
  383. */
  384. _vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
  385. Buffer[sizeof(Buffer) -1] = '\0';
  386. /*
  387. * Write trace data
  388. */
  389. IcaTraceFormat( pTraceInfo, TraceClass, TraceEnable, Buffer );
  390. }
  391. /*******************************************************************************
  392. *
  393. * _IcaStackTrace
  394. *
  395. * Write a trace record to the winstation trace file
  396. *
  397. * ENTRY:
  398. * pStack (input)
  399. * pointer to stack structure
  400. * TraceClass (input)
  401. * trace class bit mask
  402. * TraceEnable (input)
  403. * trace type bit mask
  404. * Format (input)
  405. * format string
  406. * ... (input)
  407. * enough arguments to satisfy format string
  408. *
  409. * EXIT:
  410. * nothing
  411. *
  412. ******************************************************************************/
  413. VOID _cdecl
  414. _IcaStackTrace( IN PICA_STACK pStack,
  415. IN ULONG TraceClass,
  416. IN ULONG TraceEnable,
  417. IN CHAR * Format,
  418. IN ... )
  419. {
  420. va_list arg_marker;
  421. char Buffer[256];
  422. PICA_CONNECTION pConnect;
  423. PICA_TRACE_INFO pTraceInfo;
  424. ASSERT( pStack->Header.Type == IcaType_Stack );
  425. va_start( arg_marker, Format );
  426. pConnect = IcaGetConnectionForStack( pStack );
  427. /*
  428. * Check if this trace record should be output
  429. */
  430. pTraceInfo = &pConnect->TraceInfo;
  431. if ( !(TraceClass & pTraceInfo->TraceClass) ||
  432. !(TraceEnable & pTraceInfo->TraceEnable) )
  433. return;
  434. /*
  435. * Format trace data
  436. */
  437. _vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
  438. Buffer[sizeof(Buffer) -1] = '\0';
  439. /*
  440. * Write trace data
  441. */
  442. IcaTraceFormat( pTraceInfo, TraceClass, TraceEnable, Buffer );
  443. }
  444. /*******************************************************************************
  445. *
  446. * _IcaStackTraceBuffer
  447. *
  448. * This routine conditional writes a data buffer to the trace file
  449. *
  450. * ENTRY:
  451. * pStack (input)
  452. * pointer to stack structure
  453. * TraceClass (input)
  454. * trace class bit mask
  455. * TraceEnable (input)
  456. * trace type bit mask
  457. * pBuffer (input)
  458. * pointer to data buffer
  459. * ByteCount (input)
  460. * length of buffer
  461. *
  462. * EXIT:
  463. * nothing
  464. *
  465. ******************************************************************************/
  466. VOID
  467. _IcaStackTraceBuffer( IN PICA_STACK pStack,
  468. IN ULONG TraceClass,
  469. IN ULONG TraceEnable,
  470. IN PVOID pBuffer,
  471. IN ULONG ByteCount )
  472. {
  473. PICA_CONNECTION pConnect;
  474. PICA_TRACE_INFO pTraceInfo;
  475. ASSERT( pStack->Header.Type == IcaType_Stack );
  476. pConnect = IcaGetConnectionForStack( pStack );
  477. /*
  478. * Check if this trace record should be output
  479. */
  480. pTraceInfo = &pConnect->TraceInfo;
  481. if ( !(TraceClass & pTraceInfo->TraceClass) ||
  482. !(TraceEnable & pTraceInfo->TraceEnable) )
  483. return;
  484. /*
  485. * Write trace data
  486. */
  487. _WriteHexData( pTraceInfo, pBuffer, ByteCount );
  488. }
  489. /*******************************************************************************
  490. *
  491. * _IcaChannelTrace
  492. *
  493. * Write a trace record to the winstation trace file
  494. *
  495. * ENTRY:
  496. * pChannel (input)
  497. * pointer to Channel structure
  498. * TraceClass (input)
  499. * trace class bit mask
  500. * TraceEnable (input)
  501. * trace type bit mask
  502. * Format (input)
  503. * format string
  504. * ... (input)
  505. * enough arguments to satisfy format string
  506. *
  507. * EXIT:
  508. * nothing
  509. *
  510. ******************************************************************************/
  511. VOID _cdecl
  512. _IcaChannelTrace( IN PICA_CHANNEL pChannel,
  513. IN ULONG TraceClass,
  514. IN ULONG TraceEnable,
  515. IN CHAR * Format,
  516. IN ... )
  517. {
  518. va_list arg_marker;
  519. char Buffer[256];
  520. PICA_TRACE_INFO pTraceInfo;
  521. ASSERT( pChannel->Header.Type == IcaType_Channel );
  522. va_start( arg_marker, Format );
  523. pTraceInfo = &pChannel->pConnect->TraceInfo;
  524. /*
  525. * Check if this trace record should be output
  526. */
  527. if ( !(TraceClass & pTraceInfo->TraceClass) || !(TraceEnable & pTraceInfo->TraceEnable) )
  528. return;
  529. /*
  530. * Format trace data
  531. */
  532. _vsnprintf( Buffer, sizeof(Buffer), Format, arg_marker );
  533. Buffer[sizeof(Buffer) -1] = '\0';
  534. /*
  535. * Write trace data
  536. */
  537. IcaTraceFormat( pTraceInfo, TraceClass, TraceEnable, Buffer );
  538. }
  539. /*******************************************************************************
  540. *
  541. * _IcaOpenTraceFile
  542. *
  543. * Open a trace file
  544. *
  545. * ENTRY:
  546. * pTraceInfo (input)
  547. * pointer to ICA_TRACE_INFO struct
  548. * pTraceFile (input)
  549. * pointer to trace file name
  550. *
  551. * EXIT:
  552. * STATUS_SUCCESS - no error
  553. *
  554. ******************************************************************************/
  555. #define NAMEPREFIX L"\\DosDevices\\"
  556. NTSTATUS
  557. _IcaOpenTraceFile(
  558. IN PICA_TRACE_INFO pTraceInfo,
  559. IN PWCHAR pTraceFile
  560. )
  561. {
  562. UNICODE_STRING TraceString;
  563. OBJECT_ATTRIBUTES ObjectAttributes;
  564. IO_STATUS_BLOCK iosb;
  565. HANDLE TraceFileHandle;
  566. PFILE_OBJECT pTraceFileObject;
  567. ULONG PrefixLength;
  568. ULONG TraceFileLength;
  569. NTSTATUS Status;
  570. PrefixLength = wcslen( NAMEPREFIX ) * sizeof(WCHAR);
  571. TraceFileLength = wcslen( pTraceFile ) * sizeof(WCHAR);
  572. TraceString.Length = (USHORT) (PrefixLength + TraceFileLength);
  573. TraceString.MaximumLength = TraceString.Length + sizeof(UNICODE_NULL);
  574. TraceString.Buffer = ICA_ALLOCATE_POOL( NonPagedPool, TraceString.MaximumLength );
  575. if (TraceString.Buffer != NULL) {
  576. RtlCopyMemory( TraceString.Buffer, NAMEPREFIX, PrefixLength );
  577. RtlCopyMemory( (char *)TraceString.Buffer + PrefixLength, pTraceFile, TraceFileLength );
  578. TraceString.Buffer[(PrefixLength + TraceFileLength) / sizeof(WCHAR)] = UNICODE_NULL;
  579. }
  580. else {
  581. return STATUS_NO_MEMORY;
  582. }
  583. /*
  584. * If we already have a trace file and the name is the same
  585. * as a previous call, then there's nothing to be done.
  586. */
  587. if ( pTraceInfo->pTraceFileName != NULL &&
  588. !_wcsicmp( TraceString.Buffer, pTraceInfo->pTraceFileName ) ) {
  589. ICA_FREE_POOL( TraceString.Buffer );
  590. return( STATUS_SUCCESS );
  591. }
  592. /*
  593. * Close the existing trace file if there is one
  594. */
  595. if ( pTraceInfo->pTraceFileName ) {
  596. _IcaCloseTraceFile( pTraceInfo );
  597. }
  598. InitializeObjectAttributes( &ObjectAttributes, &TraceString,
  599. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL );
  600. Status = ZwCreateFile(
  601. &TraceFileHandle,
  602. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  603. &ObjectAttributes,
  604. &iosb, // returned status information.
  605. 0, // block size (unused).
  606. 0, // file attributes.
  607. FILE_SHARE_READ | FILE_SHARE_WRITE,
  608. FILE_OVERWRITE_IF, // create disposition.
  609. 0, // create options.
  610. NULL,
  611. 0
  612. );
  613. if ( !NT_SUCCESS( Status ) ) {
  614. ICA_FREE_POOL( TraceString.Buffer );
  615. return( Status );
  616. }
  617. /*
  618. * Use the trace file handle to get a pointer to the file object.
  619. */
  620. Status = ObReferenceObjectByHandle(
  621. TraceFileHandle,
  622. 0L, // DesiredAccess
  623. *IoFileObjectType,
  624. KernelMode,
  625. (PVOID *)&pTraceFileObject,
  626. NULL
  627. );
  628. ZwClose( TraceFileHandle );
  629. if ( !NT_SUCCESS( Status ) ) {
  630. ICA_FREE_POOL( TraceString.Buffer );
  631. return( Status );
  632. }
  633. /*
  634. * Save Trace file name and file object pointer
  635. */
  636. pTraceInfo->pTraceFileName = TraceString.Buffer;
  637. pTraceInfo->pTraceFileObject = pTraceFileObject;
  638. return( STATUS_SUCCESS );
  639. }
  640. /*******************************************************************************
  641. *
  642. * _IcaCloseTraceFile
  643. *
  644. * Close a trace file
  645. *
  646. * ENTRY:
  647. * pTraceInfo (input)
  648. * pointer to ICA_TRACE_INFO struct
  649. *
  650. * EXIT:
  651. * STATUS_SUCCESS - no error
  652. *
  653. ******************************************************************************/
  654. VOID
  655. _IcaCloseTraceFile(
  656. IN PICA_TRACE_INFO pTraceInfo
  657. )
  658. {
  659. PWCHAR pTraceFileName;
  660. PFILE_OBJECT pTraceFileObject;
  661. /*
  662. * First write out any deferred trace records that exist
  663. */
  664. _IcaFlushDeferredTrace( pTraceInfo );
  665. /*
  666. * Get/reset trace info fields
  667. */
  668. pTraceFileName = pTraceInfo->pTraceFileName;
  669. pTraceFileObject = pTraceInfo->pTraceFileObject;
  670. pTraceInfo->pTraceFileName = NULL;
  671. pTraceInfo->pTraceFileObject = NULL;
  672. /*
  673. * Close trace file and free resources
  674. */
  675. ICA_FREE_POOL( pTraceFileName );
  676. ObDereferenceObject( pTraceFileObject );
  677. }
  678. /*******************************************************************************
  679. *
  680. * _IcaTraceWrite
  681. *
  682. * Write a trace file entry
  683. *
  684. * ENTRY:
  685. * pTraceInfo (input)
  686. * pointer to ICA_TRACE_INFO struct
  687. * Buffer (input)
  688. * pointer to trace buffer to write
  689. *
  690. * EXIT:
  691. * nothing
  692. *
  693. ******************************************************************************/
  694. VOID
  695. _IcaTraceWrite(
  696. IN PICA_TRACE_INFO pTraceInfo,
  697. IN PVOID Buffer
  698. )
  699. {
  700. KIRQL irql;
  701. ULONG Length;
  702. PDEFERRED_TRACE pDeferred;
  703. PDEFERRED_TRACE *ppDeferredTrace;
  704. NTSTATUS Status;
  705. /*
  706. * Write to kernel debugger if necessary
  707. */
  708. if ( pTraceInfo->fTraceDebugger )
  709. DbgPrint( "%s", Buffer );
  710. /*
  711. * If no file object pointer, then we're done
  712. */
  713. if ( pTraceInfo->pTraceFileObject == NULL )
  714. return;
  715. Length = strlen(Buffer);
  716. /*
  717. * If current Irql is DISPATCH_LEVEL or higher, then we can't
  718. * write the data now, so queue it for later writing.
  719. */
  720. irql = KeGetCurrentIrql();
  721. if ( irql >= DISPATCH_LEVEL ) {
  722. KIRQL oldIrql;
  723. /*
  724. * Allocate and initialize a deferred trace entry
  725. */
  726. pDeferred = ICA_ALLOCATE_POOL( NonPagedPool, sizeof(*pDeferred) + Length );
  727. if ( pDeferred == NULL )
  728. return;
  729. pDeferred->Next = NULL;
  730. pDeferred->Length = Length;
  731. RtlCopyMemory( pDeferred->Buffer, Buffer, Length );
  732. /*
  733. * Since the deferred list may be manipulated in
  734. * _IcaFlushDeferredTrace on behalf of an IOCTL_SYSTEM_TRACE
  735. * which does not hold any locks, IcaSpinLock is used to
  736. * ensure the list's integrity.
  737. */
  738. IcaAcquireSpinLock( &IcaTraceSpinLock, &oldIrql );
  739. /*
  740. * Add it to the end of the list
  741. */
  742. ppDeferredTrace = &pTraceInfo->pDeferredTrace;
  743. while ( *ppDeferredTrace )
  744. ppDeferredTrace = &(*ppDeferredTrace)->Next;
  745. *ppDeferredTrace = pDeferred;
  746. IcaReleaseSpinLock( &IcaTraceSpinLock, oldIrql );
  747. return;
  748. }
  749. /*
  750. * Write out any deferred trace records that exist
  751. */
  752. _IcaFlushDeferredTrace( pTraceInfo );
  753. /*
  754. * Now write the current trace buffer
  755. */
  756. CtxWriteFile( pTraceInfo->pTraceFileObject, Buffer, Length, NULL, NULL, NULL );
  757. }
  758. /*******************************************************************************
  759. *
  760. * _IcaFlushDeferredTrace
  761. *
  762. * Write any deferred trace file entries
  763. *
  764. * ENTRY:
  765. * pTraceInfo (input)
  766. * pointer to ICA_TRACE_INFO struct
  767. *
  768. * EXIT:
  769. * nothing
  770. *
  771. ******************************************************************************/
  772. VOID
  773. _IcaFlushDeferredTrace( PICA_TRACE_INFO pTraceInfo )
  774. {
  775. KIRQL oldIrql;
  776. PDEFERRED_TRACE pDeferred;
  777. IcaAcquireSpinLock( &IcaTraceSpinLock, &oldIrql );
  778. while ( (pDeferred = pTraceInfo->pDeferredTrace) ) {
  779. pTraceInfo->pDeferredTrace = pDeferred->Next;
  780. IcaReleaseSpinLock( &IcaTraceSpinLock, oldIrql );
  781. CtxWriteFile( pTraceInfo->pTraceFileObject, pDeferred->Buffer,
  782. pDeferred->Length, NULL, NULL, NULL );
  783. ICA_FREE_POOL( pDeferred );
  784. IcaAcquireSpinLock( &IcaTraceSpinLock, &oldIrql );
  785. }
  786. IcaReleaseSpinLock( &IcaTraceSpinLock, oldIrql );
  787. }
  788. /*******************************************************************************
  789. *
  790. * _FormatTime
  791. *
  792. * format current time into buffer
  793. *
  794. * ENTRY:
  795. * pBuffer (output)
  796. * pointer to buffer
  797. * Length (input)
  798. * length of buffer
  799. *
  800. * EXIT:
  801. * length of formated time
  802. *
  803. ******************************************************************************/
  804. int
  805. _FormatTime( CHAR * pBuffer, ULONG Length )
  806. {
  807. LARGE_INTEGER SystemTime;
  808. LARGE_INTEGER LocalTime;
  809. TIME_FIELDS TimeFields;
  810. int len;
  811. /*
  812. * Get local time
  813. */
  814. KeQuerySystemTime( &SystemTime );
  815. ExSystemTimeToLocalTime( &SystemTime, &LocalTime );
  816. RtlTimeToTimeFields( &LocalTime, &TimeFields );
  817. /*
  818. * Format buffer
  819. */
  820. len = _snprintf( pBuffer,
  821. Length,
  822. "%02d:%02d:%02d.%03d ",
  823. TimeFields.Hour,
  824. TimeFields.Minute,
  825. TimeFields.Second,
  826. TimeFields.Milliseconds );
  827. return( len );
  828. }
  829. /*******************************************************************************
  830. *
  831. * _FormatThreadId
  832. *
  833. * format thread id into buffer
  834. *
  835. * ENTRY:
  836. * pBuffer (output)
  837. * pointer to buffer
  838. * Length (input)
  839. * length of buffer
  840. *
  841. * EXIT:
  842. * length of formated time
  843. *
  844. ******************************************************************************/
  845. #define TEB_CLIENTID_OFFSET 0x1e0
  846. int
  847. _FormatThreadId( CHAR * pBuffer, ULONG Length )
  848. {
  849. PCLIENT_ID pClientId;
  850. char Number[40]; //on WIN64, %p is 16 chars, we need two of these. So 32 + 2 bytes for "." and "\0". Use 40 just in case
  851. int len;
  852. /*
  853. * Get pointer to clientid structure in teb
  854. * - use hardcoded teb offset
  855. */
  856. pClientId = (PCLIENT_ID) ((char*)PsGetCurrentThread() + TEB_CLIENTID_OFFSET);
  857. /*
  858. * Format buffer
  859. */
  860. _snprintf( Number, sizeof(Number), "%p.%p",
  861. pClientId->UniqueProcess, pClientId->UniqueThread );
  862. Number[39] = '\0';
  863. len = _snprintf( pBuffer, Length, "%-7s ", Number );
  864. return( len );
  865. }
  866. /*******************************************************************************
  867. *
  868. * _WriteHexData
  869. *
  870. * format and write hex data
  871. *
  872. * ENTRY:
  873. * pTraceInfo (input)
  874. * pointer to ICA_TRACE_INFO struct
  875. * pBuffer (output)
  876. * pointer to buffer
  877. * Length (input)
  878. * length of buffer
  879. *
  880. * EXIT:
  881. * length of formated time
  882. *
  883. ******************************************************************************/
  884. VOID
  885. _WriteHexData(
  886. IN PICA_TRACE_INFO pTraceInfo,
  887. IN PVOID pBuffer,
  888. IN ULONG ByteCount
  889. )
  890. {
  891. PUCHAR pData;
  892. ULONG i;
  893. ULONG j;
  894. char Buffer[256];
  895. /*
  896. * Output data
  897. */
  898. pData = (PUCHAR) pBuffer;
  899. for ( i=0; i < ByteCount; i += 16 ) {
  900. ULONG c = 0;
  901. for ( j=0; j < 16 && (i+j) < ByteCount; j++ )
  902. c += _snprintf( &Buffer[c], sizeof(Buffer)-c, "%02X ", pData[j] );
  903. for ( ; j < 16; j++ ) {
  904. Buffer[c++] = ' ';
  905. Buffer[c++] = ' ';
  906. Buffer[c++] = ' ';
  907. }
  908. Buffer[c++] = ' ';
  909. Buffer[c++] = ' ';
  910. for ( j=0; j < 16 && (i+j) < ByteCount; j++, pData++ ) {
  911. if ( *pData < 0x20 || *pData > 0x7f )
  912. Buffer[c++] = '.';
  913. else
  914. Buffer[c++] = *pData;
  915. }
  916. Buffer[c++] = '\n';
  917. Buffer[c++] = '\0';
  918. _IcaTraceWrite( pTraceInfo, Buffer );
  919. }
  920. }