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.

1435 lines
32 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. debug.c
  5. Abstract:
  6. Domain Name System (DNS) Library
  7. Debug routines.
  8. Author:
  9. Jim Gilroy (jamesg) January 31, 1995
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. #define DNSDBG_CONTEXT_SWITCH_LOGGING 1
  14. #define DNSDBG_DEFAULT_WRAP_SIZE (2000000) // 2mb
  15. //
  16. // DCR: Temp hack while debugging print lock jam
  17. // - cuts off lock printing to avoid recursive spin
  18. //
  19. extern PCRITICAL_SECTION pDnsAtomicPrintCs;
  20. //
  21. // Debug globals
  22. //
  23. DNS_DEBUG_INFO g_DnsDbgInfo = { 0 };
  24. PDNS_DEBUG_INFO g_pDbgInfo = &g_DnsDbgInfo;
  25. // Redirected
  26. BOOL g_DbgRedirected = FALSE;
  27. //
  28. // Debug flag -- exposed as pointer in dnslib.h
  29. //
  30. // By default use DnsDebugFlag, but actual debug printing is
  31. // switched by *pDnsDebugFlag, which caller may point at local
  32. // flag if desired.
  33. //
  34. PDWORD pDnsDebugFlag = (PDWORD)&g_DnsDbgInfo;
  35. //
  36. // Note that in all functions below, we use the universal
  37. // check IS_DNSDBG_ON(), which is defined for debug AND retail.
  38. // Do NOT use any of the debug macros, as we want the code to
  39. // work equally well in retail versions of dnsapi.dll, so that
  40. // debug versions of calling modules can use these functions.
  41. //
  42. //
  43. // Print buffer sizes
  44. // - small default stack buffer
  45. // - large buffer on heap to handle any print
  46. //
  47. // NOTE: MUST have stack buffer of sufficient size to
  48. // handle any message we print on memory allocation
  49. // failure; otherwise we get into the obvious loop
  50. // of alloc failure causing print, which causes attempted
  51. // alloc and another print
  52. //
  53. #define DNS_STACK_PRINT_BUFFER_LENGTH (0x300) // 768 covers 99%
  54. #define DNS_HEAP_PRINT_BUFFER_LENGTH (0x4000) // 16K will cover anything
  55. //
  56. // Public debug routines
  57. //
  58. VOID
  59. Dns_Assert(
  60. IN LPSTR pszFile,
  61. IN INT LineNo,
  62. IN LPSTR pszExpr
  63. )
  64. {
  65. DnsDbg_Printf(
  66. "ASSERTION FAILED: %s\n"
  67. " %s, line %d\n",
  68. pszExpr,
  69. pszFile,
  70. LineNo );
  71. DnsDbg_Flush();
  72. // always print to debugger, even if debugger print flag not set
  73. if ( ! IS_DNSDBG_ON( DEBUGGER ) )
  74. {
  75. DnsDbg_PrintfToDebugger(
  76. "ASSERTION FAILED: %s\n"
  77. " %s, line %d\n",
  78. pszExpr,
  79. pszFile,
  80. LineNo );
  81. }
  82. if ( IS_DNSDBG_ON( BREAKPOINTS ) )
  83. {
  84. DebugBreak();
  85. }
  86. else
  87. {
  88. DnsDbg_Printf( "Skipping DNS_ASSERT, debug flag = %lx\n", *pDnsDebugFlag );
  89. }
  90. }
  91. #if 0
  92. typedef struct _DnsDebugInit
  93. {
  94. DWORD Flag;
  95. PSTR pszFlagFile;
  96. PDWORD pDebugFlag;
  97. PSTR pszLogFile;
  98. DWORD WrapSize;
  99. BOOL fUseGlobalFile;
  100. BOOL fUseGlobalFlag;
  101. BOOL fSetGlobals;
  102. }
  103. DNS_DEBUG_INIT, *PDNS_DEBUG_INIT;
  104. #endif
  105. VOID
  106. Dns_StartDebugEx(
  107. IN DWORD DebugFlag,
  108. IN PSTR pszFlagFile,
  109. IN OUT PDWORD pDebugFlag,
  110. IN PSTR pszLogFile,
  111. IN DWORD WrapSize,
  112. IN BOOL fUseGlobalFile,
  113. IN BOOL fUseGlobalFlag,
  114. IN BOOL fSetGlobals
  115. )
  116. /*++
  117. Routine Description:
  118. Initialize debugging.
  119. Only current task is to read and set debug flags.
  120. Arguments:
  121. includes:
  122. dwFlag -- debug flags
  123. pszFlagFile -- name of file containing debug flags
  124. pdwFlag -- ptr to DWORD to receive debug flags
  125. pszLogFile -- log file name
  126. dwWrapSize -- log file wrap size
  127. fUseGlobalFile --
  128. fUseGlobalFlag --
  129. fSetGlobals --
  130. Return Value:
  131. None.
  132. --*/
  133. {
  134. HANDLE hfile;
  135. DWORD freadFlag = FALSE;
  136. BOOL fretry = FALSE;
  137. CHAR prevName[ MAX_PATH+10 ];
  138. DWORD debugFlag;
  139. PDNS_DEBUG_INFO pinfoGlobal = NULL;
  140. //
  141. // use external flag?
  142. // - save ptr to it
  143. //
  144. // allow use of external flag so callers -- eg. DNS server --
  145. // can easily manipulate flag during run time and still keep
  146. // their checking macros simple
  147. //
  148. if ( pDebugFlag )
  149. {
  150. pDnsDebugFlag = pDebugFlag;
  151. g_DnsDbgInfo.Flag = *pDnsDebugFlag;
  152. }
  153. //
  154. // get piggyback info
  155. //
  156. if ( fUseGlobalFlag || fUseGlobalFile )
  157. {
  158. pinfoGlobal = DnsApiSetDebugGlobals( NULL );
  159. }
  160. //
  161. // skip debug flag setup if piggybacking
  162. // - use the existing flag value
  163. // - but not safe to grab pointer which
  164. // may go away on dll unload
  165. //
  166. // DCR: safe way to use existing flags?
  167. // DCR: need to be able to get "last" debug flag set
  168. // without blowing up
  169. //
  170. if ( fUseGlobalFlag &&
  171. pinfoGlobal &&
  172. pinfoGlobal->hFile )
  173. {
  174. goto Done;
  175. }
  176. //
  177. // setup debug flag
  178. //
  179. debugFlag = DebugFlag;
  180. if ( debugFlag )
  181. {
  182. freadFlag = TRUE;
  183. }
  184. else if ( pszFlagFile )
  185. {
  186. // read debug flag in file
  187. hfile = CreateFile(
  188. pszFlagFile,
  189. GENERIC_READ,
  190. FILE_SHARE_READ,
  191. NULL,
  192. OPEN_EXISTING,
  193. 0,
  194. NULL
  195. );
  196. if ( hfile == (HANDLE)INVALID_HANDLE_VALUE )
  197. {
  198. // if file specified and not found, then quit if explicit value
  199. // not given
  200. if ( debugFlag == 0 )
  201. {
  202. return;
  203. }
  204. }
  205. else
  206. {
  207. DWORD bytesRead;
  208. CHAR buffer[100];
  209. RtlZeroMemory( buffer, sizeof(buffer) );
  210. if ( ReadFile( hfile, buffer, 100, &bytesRead, NULL ) )
  211. {
  212. buffer[bytesRead] = '\0';
  213. debugFlag = strtoul( buffer, NULL, 16 );
  214. freadFlag = TRUE;
  215. }
  216. else
  217. {
  218. DnsDbg_Printf( "read file failed: %ld\n", GetLastError( ) );
  219. if ( debugFlag == 0 )
  220. {
  221. CloseHandle( hfile );
  222. return;
  223. }
  224. }
  225. CloseHandle( hfile );
  226. }
  227. }
  228. //
  229. // save any flag read
  230. // - reset global (internal or external) to it
  231. //
  232. if ( freadFlag )
  233. {
  234. g_DnsDbgInfo.Flag = debugFlag;
  235. *pDnsDebugFlag = debugFlag;
  236. }
  237. //
  238. // skip debug file open if piggybacking
  239. //
  240. // two levels
  241. // - only using file
  242. // - using file and debug flags
  243. if ( fUseGlobalFile &&
  244. pinfoGlobal &&
  245. pinfoGlobal->hFile )
  246. {
  247. goto Done;
  248. }
  249. //
  250. // open debug logfile
  251. //
  252. fretry = 0;
  253. while ( pszLogFile )
  254. {
  255. PCHAR pnameBuf = g_DnsDbgInfo.FileName;
  256. // heap may not be initialized, copy filename to static buffer
  257. //
  258. // note: if we fail on first pass we try again but open directly
  259. // at file system root; given simply filename, applications
  260. // run from system32 and services (resolver) will attempt open
  261. // in system32 and some (resolver) do not by default have
  262. // permissions to create files there
  263. if ( fretry == 0 )
  264. {
  265. strncpy( pnameBuf, pszLogFile, MAX_PATH );
  266. }
  267. else
  268. {
  269. pnameBuf[0] = '\\';
  270. strncpy( pnameBuf+1, pszLogFile, MAX_PATH-1 );
  271. }
  272. pnameBuf[MAX_PATH-1] = 0;
  273. #if 0
  274. // jeff changes -- don't have time to fix up now
  275. // file wrapping should handle this sort of thing
  276. //
  277. // Save off the current copy as ".prev"
  278. //
  279. strncpy( prevName, DnsDebugFileName, MAX_PATH );
  280. strcat( prevName, ".prev" );
  281. MoveFileEx(
  282. DnsDebugFileName,
  283. prevName,
  284. MOVEFILE_REPLACE_EXISTING );
  285. DnsDebugFileHandle = CreateFile(
  286. DnsDebugFileName,
  287. GENERIC_READ | GENERIC_WRITE,
  288. FILE_SHARE_READ,
  289. NULL,
  290. CREATE_ALWAYS,
  291. 0,
  292. NULL
  293. );
  294. #endif
  295. hfile = CreateFile(
  296. pnameBuf,
  297. GENERIC_READ | GENERIC_WRITE,
  298. FILE_SHARE_READ,
  299. NULL,
  300. CREATE_ALWAYS,
  301. 0,
  302. NULL
  303. );
  304. // on failure, retry once
  305. if ( hfile == NULL || hfile == (HANDLE)INVALID_HANDLE_VALUE )
  306. {
  307. if ( !fretry )
  308. {
  309. fretry++;
  310. continue;
  311. }
  312. hfile = NULL;
  313. }
  314. g_DnsDbgInfo.hFile = hfile;
  315. g_DnsDbgInfo.FileWrapSize = WrapSize;
  316. break;
  317. }
  318. //
  319. // initialize console
  320. //
  321. if ( IS_DNSDBG_ON( CONSOLE ) )
  322. {
  323. CONSOLE_SCREEN_BUFFER_INFO csbi;
  324. COORD coord;
  325. AllocConsole();
  326. GetConsoleScreenBufferInfo(
  327. GetStdHandle(STD_OUTPUT_HANDLE),
  328. &csbi
  329. );
  330. coord.X = (SHORT)(csbi.srWindow.Right - csbi.srWindow.Left + 1);
  331. coord.Y = (SHORT)((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) * 20);
  332. SetConsoleScreenBufferSize(
  333. GetStdHandle(STD_OUTPUT_HANDLE),
  334. coord
  335. );
  336. g_DnsDbgInfo.fConsole = TRUE;
  337. }
  338. //
  339. // set "global" debug file info
  340. //
  341. // dnsapi.dll serves as storage for common dns client
  342. // debug file if that is desired; this lets applications
  343. // push all dns debug output into a single file
  344. //
  345. // currently push both file and debug flag value
  346. // note, we don't push debug file ptr as don't know
  347. // whose memory becomes invalid first
  348. //
  349. if ( fSetGlobals && g_DnsDbgInfo.hFile )
  350. {
  351. DnsApiSetDebugGlobals(
  352. &g_DnsDbgInfo // set our info as global
  353. );
  354. }
  355. Done:
  356. //
  357. // use "global" (dnsapi.dll) debugging
  358. // - copy in our info if no existing info
  359. // - set to use global info blob
  360. //
  361. // two levels
  362. // - only using file
  363. // - using file and debug flags
  364. if ( fUseGlobalFile &&
  365. pinfoGlobal )
  366. {
  367. // copy in our new info if no global info exists
  368. if ( !pinfoGlobal->hFile &&
  369. g_DnsDbgInfo.hFile )
  370. {
  371. DnsApiSetDebugGlobals( &g_DnsDbgInfo );
  372. }
  373. // point at global info
  374. g_pDbgInfo = pinfoGlobal;
  375. g_DbgRedirected = TRUE;
  376. if ( fUseGlobalFlag )
  377. {
  378. pDnsDebugFlag = (PDWORD) pinfoGlobal;
  379. }
  380. // avoid double cleanup
  381. // - clear the handle in your modules blob
  382. g_DnsDbgInfo.hFile = NULL;
  383. }
  384. //
  385. // use print locking for debug locking
  386. //
  387. DnsPrint_InitLocking( NULL );
  388. DNSDBG( ANY, (
  389. "Initialized debugging:\n"
  390. "\tpDbgInfo %p\n"
  391. "\t&DnsDbgInfo %p\n"
  392. "\tfile (param) %s\n"
  393. "\thFile %p\n"
  394. "\tpDbgInfo->Flag %08x\n"
  395. "\tpDnsDebugFlag %p\n"
  396. "\t*pDnsDebugFlag %08x\n"
  397. "DnsLib compiled on %s at %s\n",
  398. g_pDbgInfo,
  399. &g_DnsDbgInfo,
  400. pszLogFile,
  401. g_pDbgInfo->hFile,
  402. g_pDbgInfo->Flag,
  403. pDnsDebugFlag,
  404. *pDnsDebugFlag,
  405. __DATE__,
  406. __TIME__ ));
  407. } // Dns_StartDebug
  408. #if 0
  409. VOID
  410. Dns_StartDebugEx(
  411. IN DWORD dwFlag,
  412. IN PSTR pszFlagFile,
  413. IN OUT PDWORD pdwFlag,
  414. IN PSTR pszLogFile,
  415. IN DWORD dwWrapSize,
  416. IN BOOL fUseGlobalFile,
  417. IN BOOL fUseGlobalFlag,
  418. IN BOOL fSetGlobals
  419. )
  420. /*++
  421. Routine Description:
  422. Initialize debugging.
  423. Only current task is to read and set debug flags.
  424. Arguments:
  425. dwFlag -- debug flags
  426. pszFlagFile -- name of file containing debug flags
  427. pdwFlag -- ptr to DWORD to receive debug flags
  428. pszLogFile -- log file name
  429. dwWrapSize -- log file wrap size
  430. Return Value:
  431. None.
  432. --*/
  433. {
  434. DNS_DEBUG_INIT info;
  435. RtlZeroMemory
  436. &info,
  437. sizeof(info) );
  438. info.pszFlagFile = pszFlagFile;
  439. info.DebugFlags = dwFlag;
  440. info.pDebugFlags = pdwFlag;
  441. info.pszLogFile = pszLogFile;
  442. info.dwWrapSize = dwWrapSize;
  443. info.fUseGlobalFile = fUseGlobalFile;
  444. info.fUseGlobalFlag = fUseGlobalFlag;
  445. info.fSetGlobals = fSetGlobals;
  446. privateStartDebug( &info );
  447. }
  448. #endif
  449. VOID
  450. Dns_StartDebug(
  451. IN DWORD dwFlag,
  452. IN PSTR pszFlagFile,
  453. IN OUT PDWORD pdwFlag,
  454. IN PSTR pszLogFile,
  455. IN DWORD dwWrapSize
  456. )
  457. /*++
  458. Routine Description:
  459. Initialize debugging.
  460. Only current task is to read and set debug flags.
  461. Arguments:
  462. dwFlag -- debug flags
  463. pszFlagFile -- name of file containing debug flags
  464. pdwFlag -- ptr to DWORD to receive debug flags
  465. pszLogFile -- log file name
  466. dwWrapSize -- log file wrap size
  467. Return Value:
  468. None.
  469. --*/
  470. {
  471. Dns_StartDebugEx(
  472. dwFlag,
  473. pszFlagFile,
  474. pdwFlag,
  475. pszLogFile,
  476. dwWrapSize,
  477. FALSE,
  478. FALSE,
  479. FALSE );
  480. }
  481. VOID
  482. Dns_EndDebug(
  483. VOID
  484. )
  485. /*++
  486. Routine Description:
  487. Terminate DNS debugging for shutdown.
  488. Close debug file.
  489. Arguments:
  490. None.
  491. Return Value:
  492. None.
  493. --*/
  494. {
  495. // close file
  496. // - but only your dnslib instance
  497. // - shared global file is closed by dnsapi
  498. if ( g_DnsDbgInfo.hFile )
  499. {
  500. CloseHandle( g_DnsDbgInfo.hFile );
  501. g_DnsDbgInfo.hFile = NULL;
  502. }
  503. }
  504. PDNS_DEBUG_INFO
  505. Dns_SetDebugGlobals(
  506. IN OUT PDNS_DEBUG_INFO pInfo
  507. )
  508. /*++
  509. Routine Description:
  510. Exposure of debug globals.
  511. The purpose of this is to allow dnsapi.dll to use it's globals
  512. to allow common debug file. I'm using one routine for both
  513. get and set to mimize the interfaces.
  514. Note however, that this is NOT the routine that routines in
  515. this module use to get cross-module debugging. They MUST call
  516. the actual dnsapi.dll routine so that they are attaching
  517. to the dnsapi's dnslib debugging globls not the ones with the
  518. dnslib statically linked into their module.
  519. Arguments:
  520. pInfo -- local info to use as global info
  521. Return Value:
  522. Ptr to global info
  523. --*/
  524. {
  525. //
  526. // verify valid info coming in
  527. // - must have file handle
  528. //
  529. //
  530. // Implementation note:
  531. //
  532. // There are several issues to deal with when doing this
  533. // - multiple redirection
  534. // getting everyone to point at same blob
  535. // solutions:
  536. // - either double pointer (they read dnsapi.dll
  537. // pointer
  538. // - copy into dnsapi.dll the info
  539. // - locking
  540. // - broad scale print of structs
  541. // - cleanup
  542. // - no double close of handle
  543. // - memory sections disappearing while some dll
  544. // or exe still printing
  545. //
  546. // Approachs:
  547. // 1) redirect blob pointer
  548. // blob could expand to include actual print locks
  549. // 2) copy info into single blob
  550. // 3) expose debug routines
  551. //
  552. //
  553. // Perhaps best approach might be to expose the dnsapi.dll
  554. // printing
  555. // - solves locking (at detail level), doesn't prevent breakup
  556. // of high level printing unless it also redirected
  557. // - can be done at the private level after parsing to va_arg
  558. // - solves all the cleanup
  559. // - they can be dumb stubs in non-debug binary, and dnslib
  560. // routines can default to self if can't call dnsapi.dll
  561. // routines
  562. //
  563. // Then redirection is simply
  564. // - yes i use it -- redirection on each use
  565. // - i want my file (and params) to BE used
  566. //
  567. #if 1
  568. //
  569. // copy over "i-want-to-be-global" callers context
  570. //
  571. // note: we're in dnsapi.dll here and should always be
  572. // pointed at our own context -- we can change that
  573. // later if desired
  574. //
  575. // note
  576. // - lock during copy to be safe
  577. // - don't leak existing handle
  578. // - protect global handle from double close
  579. //
  580. if ( pInfo )
  581. {
  582. DnsPrint_Lock();
  583. DNS_ASSERT( g_pDbgInfo == &g_DnsDbgInfo );
  584. if ( pInfo->hFile )
  585. {
  586. HANDLE htemp = g_pDbgInfo->hFile;
  587. RtlCopyMemory(
  588. & g_DnsDbgInfo,
  589. pInfo,
  590. sizeof(*pInfo) );
  591. g_pDbgInfo = &g_DnsDbgInfo;
  592. pDnsDebugFlag = (PDWORD)&g_DnsDbgInfo;
  593. CloseHandle( htemp );
  594. }
  595. DnsPrint_Unlock();
  596. }
  597. #else
  598. //
  599. // point dnsapi.dll debugging global at this context
  600. // which becomes "global"
  601. // note: essential this is last writer wins, but this
  602. // should be fine for our purpuse (dnsup and resolver)
  603. // as these processes init the debug after the
  604. // dll loads
  605. //
  606. // problem with this approach is that folks redirected
  607. // onto dnsapi.dll do not get new info when it is
  608. // redirected (into dnsup)
  609. if ( pInfo && pInfo->hFile )
  610. {
  611. g_pDbgInfo = pInfo;
  612. pDnsDebugFlag = (PDWORD)pInfo;
  613. }
  614. #endif
  615. return g_pDbgInfo;
  616. }
  617. #if 0
  618. VOID
  619. privateSyncGlobalDebug(
  620. VOID
  621. )
  622. /*++
  623. Routine Description:
  624. Sync up with global debug.
  625. Get dnslib debugging in line with "global" debugging if
  626. that is desired for this dnslib instance.
  627. Arguments:
  628. None.
  629. Return Value:
  630. None
  631. --*/
  632. {
  633. if ( !g_DbgRedirected )
  634. {
  635. return;
  636. }
  637. // sync with global values
  638. }
  639. #endif
  640. VOID
  641. DnsDbg_WrapLogFile(
  642. VOID
  643. )
  644. /*++
  645. Routine Description:
  646. Wrap the log file.
  647. Arguments:
  648. None.
  649. Return Value:
  650. None.
  651. --*/
  652. {
  653. CHAR backupName[ MAX_PATH+10 ];
  654. HANDLE hfile;
  655. //
  656. // note, need to lock as file handle used in DnsDbg_Flush()
  657. // outside print routine
  658. //
  659. DnsPrint_Lock();
  660. hfile = g_pDbgInfo->hFile;
  661. if ( hfile )
  662. {
  663. FlushFileBuffers( hfile );
  664. CloseHandle( hfile );
  665. }
  666. strcpy( backupName, g_pDbgInfo->FileName );
  667. if ( g_pDbgInfo->FileWrapCount == 0 )
  668. {
  669. strcat( backupName, ".first" );
  670. }
  671. else
  672. {
  673. strcat( backupName, ".last" );
  674. }
  675. MoveFileEx(
  676. g_pDbgInfo->FileName,
  677. backupName,
  678. MOVEFILE_REPLACE_EXISTING
  679. );
  680. hfile = CreateFile(
  681. g_pDbgInfo->FileName,
  682. GENERIC_READ | GENERIC_WRITE,
  683. FILE_SHARE_READ,
  684. NULL,
  685. CREATE_ALWAYS,
  686. 0,
  687. NULL
  688. );
  689. if ( hfile == (HANDLE)INVALID_HANDLE_VALUE )
  690. {
  691. hfile = NULL;
  692. }
  693. g_pDbgInfo->hFile = hfile;
  694. g_pDbgInfo->FileWrapCount++;
  695. g_pDbgInfo->FileCurrentSize = 0;
  696. DnsPrint_Unlock();
  697. }
  698. VOID
  699. privateDnsDebugPrint(
  700. IN PBYTE pOutputBuffer,
  701. IN BOOL fPrintContext
  702. )
  703. /*++
  704. Routine Description:
  705. Private DNS debug print that does actual print.
  706. May print to any of
  707. - debugger
  708. - console window
  709. - debug log file
  710. Arguments:
  711. pOutputBuffer -- bytes to print
  712. fPrintContext
  713. - TRUE to print thread context
  714. - FALSE otherwise
  715. Return Value:
  716. None.
  717. --*/
  718. {
  719. DWORD length;
  720. BOOL ret;
  721. //
  722. // DCR: nice to automatically shut down console print when debugging
  723. // it would be cool to be able to have all flags on, and detect
  724. // when in ntsd, so that we don't get duplicated output
  725. //
  726. //
  727. // lock print to keep atomic even during wrap
  728. // - note use Print lock, which exists even in retail builds
  729. // Dbg lock is defined away
  730. //
  731. DnsPrint_Lock();
  732. //
  733. // catch and timestamp thread context switches
  734. //
  735. if ( fPrintContext )
  736. {
  737. DWORD threadId = GetCurrentThreadId();
  738. BOOL fcontextSwitch = (g_pDbgInfo->LastThreadId != threadId);
  739. SYSTEMTIME st;
  740. BOOL fdoPrint = FALSE;
  741. // get time
  742. // - if have context switch
  743. // - or putting in debug timestamps
  744. //
  745. // DCR: maybe have global that set to put in timestamps and
  746. // can set interval
  747. //
  748. // DCR: lock safe timestamps
  749. // better would be "lock-safe" timestamps that are printed
  750. // only when take the print lock -- then they would never
  751. // interrupt the a multi-part print
  752. // one way might be to test recursive depth of print CS
  753. // otherwise must change to lock that includes this
  754. // code
  755. if ( fcontextSwitch
  756. ||
  757. (pDnsDebugFlag && (*pDnsDebugFlag & DNS_DBG_TIMESTAMP)) )
  758. {
  759. GetLocalTime( &st );
  760. if ( g_pDbgInfo->LastSecond != st.wSecond )
  761. {
  762. fdoPrint = TRUE;
  763. }
  764. }
  765. if ( fcontextSwitch || fdoPrint )
  766. {
  767. CHAR printBuffer[ 200 ];
  768. length = sprintf(
  769. printBuffer,
  770. fcontextSwitch ?
  771. "\n%02d:%02d:%02d:%03d DBG switch from thread %X to thread %X\n" :
  772. "%02d:%02d:%02d:%03d DBG tick\n",
  773. st.wHour,
  774. st.wMinute,
  775. st.wSecond,
  776. st.wMilliseconds,
  777. g_pDbgInfo->LastThreadId,
  778. threadId );
  779. g_pDbgInfo->LastSecond = st.wSecond;
  780. g_pDbgInfo->LastThreadId = threadId;
  781. // print context
  782. // - suppress context even through thread test
  783. // would break recursion
  784. privateDnsDebugPrint(
  785. printBuffer,
  786. FALSE // suppress context
  787. );
  788. }
  789. }
  790. //
  791. // output -- to debugger, console, file
  792. //
  793. if ( IS_DNSDBG_ON( DEBUGGER ) )
  794. {
  795. OutputDebugString( pOutputBuffer );
  796. }
  797. if ( IS_DNSDBG_ON( CONSOLE ) )
  798. {
  799. if ( g_pDbgInfo->fConsole )
  800. {
  801. length = strlen( pOutputBuffer );
  802. ret = WriteFile(
  803. GetStdHandle(STD_OUTPUT_HANDLE),
  804. (PVOID) pOutputBuffer,
  805. length,
  806. &length,
  807. NULL
  808. );
  809. #if 0
  810. if ( !ret )
  811. {
  812. DnsDbg_PrintfToDebugger(
  813. "DnsDbg_Printf: console WriteFile failed: %ld\n",
  814. GetLastError() );
  815. }
  816. #endif
  817. }
  818. }
  819. //
  820. // write to debug log
  821. //
  822. if ( IS_DNSDBG_ON( FILE ) )
  823. {
  824. if ( g_pDbgInfo->hFile )
  825. {
  826. length = strlen( pOutputBuffer );
  827. ret = WriteFile(
  828. g_pDbgInfo->hFile,
  829. (PVOID) pOutputBuffer,
  830. length,
  831. &length,
  832. NULL
  833. );
  834. if ( !ret )
  835. {
  836. DnsDbg_PrintfToDebugger(
  837. "DnsDbg_Printf: file WriteFile failed: %ld\n",
  838. GetLastError() );
  839. }
  840. //
  841. // if wrapping debug log file
  842. // - move current log to backup file
  843. // <file>.first on first wrap
  844. // <file>.last on subsequent wraps
  845. // - reopen current file name
  846. //
  847. g_pDbgInfo->FileCurrentSize += length;
  848. if ( g_pDbgInfo->FileWrapSize &&
  849. g_pDbgInfo->FileWrapSize <= g_pDbgInfo->FileCurrentSize )
  850. {
  851. DnsDbg_WrapLogFile();
  852. }
  853. else if ( IS_DNSDBG_ON( FLUSH ) )
  854. {
  855. FlushFileBuffers( g_pDbgInfo->hFile );
  856. }
  857. }
  858. }
  859. DnsPrint_Unlock();
  860. } // privateDnsDebugPrint
  861. VOID
  862. privateFormatAndPrintBuffer(
  863. IN LPSTR Format,
  864. IN va_list ArgList
  865. )
  866. /*++
  867. Routine Description:
  868. Arguments to formatted buffer print.
  869. This helper routine exists to avoid duplicating buffer
  870. overflow logic in DnsDbg_Printf() and DnsDbg_PrintRoutine()
  871. The overflow logic is required because the default stack size
  872. has been chopped down in whistler making is easy to generate
  873. stack expansion exceptions under stress. And of course this
  874. means the stress guys send me these B.S. stress failures.
  875. Solution is to put a small buffer on the stack for perf, then
  876. allocate a larger buffer if the print doesn't fit into the
  877. stack buffer.
  878. Arguments:
  879. Format -- standard C format string
  880. ArgList -- standard arg list
  881. Return Value:
  882. None.
  883. --*/
  884. {
  885. CHAR stackBuffer[ DNS_STACK_PRINT_BUFFER_LENGTH ];
  886. ULONG bufLength;
  887. DWORD lastError;
  888. INT count;
  889. PCHAR pprintBuffer;
  890. PCHAR pheapBuffer = NULL;
  891. //
  892. // save last error so any WriteFile() failures don't mess it up
  893. //
  894. lastError = GetLastError();
  895. //
  896. // write formatted print buffer
  897. //
  898. // - first try stack buffer
  899. // - if fails, try heap buffer
  900. // - use best, always NULL terminate
  901. //
  902. bufLength = DNS_STACK_PRINT_BUFFER_LENGTH;
  903. pprintBuffer = stackBuffer;
  904. do
  905. {
  906. #if 0
  907. // code for debugging print lock problems
  908. PBYTE ptemp = pprintBuffer;
  909. if ( pDnsAtomicPrintCs )
  910. {
  911. ptemp += sprintf(
  912. ptemp,
  913. "(%d) ",
  914. pDnsAtomicPrintCs->RecursionCount
  915. );
  916. }
  917. count = _vsnprintf(
  918. ptemp,
  919. bufLength-1-(ptemp-pprintBuffer),
  920. Format,
  921. ArgList );
  922. #else
  923. count = _vsnprintf(
  924. pprintBuffer,
  925. bufLength-1,
  926. Format,
  927. ArgList );
  928. #endif
  929. pprintBuffer[ bufLength-1 ] = 0;
  930. if ( count > 0 || pheapBuffer )
  931. {
  932. break;
  933. }
  934. // try again with heap buffer
  935. pheapBuffer = ALLOCATE_HEAP( DNS_HEAP_PRINT_BUFFER_LENGTH );
  936. if ( !pheapBuffer )
  937. {
  938. break;
  939. }
  940. pprintBuffer = pheapBuffer;
  941. bufLength = DNS_HEAP_PRINT_BUFFER_LENGTH;
  942. }
  943. while( 1 );
  944. va_end( ArgList );
  945. // do the real print
  946. privateDnsDebugPrint( pprintBuffer, TRUE );
  947. if ( pheapBuffer )
  948. {
  949. FREE_HEAP( pheapBuffer );
  950. }
  951. // restore LastError() if changed
  952. if ( lastError != GetLastError() )
  953. {
  954. SetLastError( lastError );
  955. }
  956. }
  957. VOID
  958. DnsDbg_Printf(
  959. IN LPSTR Format,
  960. ...
  961. )
  962. /*++
  963. Routine Description:
  964. DNS debug print with printf semantics.
  965. May print to any of
  966. - debugger
  967. - console window
  968. - debug log file
  969. Arguments:
  970. pContext -- dummny context to match signature of PRINT_ROUTINE function
  971. Format -- standard C format string
  972. ... -- standard arg list
  973. Return Value:
  974. None.
  975. --*/
  976. {
  977. va_list arglist;
  978. va_start( arglist, Format );
  979. privateFormatAndPrintBuffer(
  980. Format,
  981. arglist );
  982. }
  983. VOID
  984. DnsDbg_PrintRoutine(
  985. IN OUT PPRINT_CONTEXT pContext,
  986. IN LPSTR Format,
  987. ...
  988. )
  989. /*++
  990. Routine Description:
  991. DNS debug print with PRINT_ROUTINE semantics.
  992. Arguments:
  993. pContext -- dummny context to match signature of PRINT_ROUTINE function
  994. Format -- standard C format string
  995. ... -- standard arg list
  996. Return Value:
  997. None.
  998. --*/
  999. {
  1000. va_list arglist;
  1001. va_start( arglist, Format );
  1002. privateFormatAndPrintBuffer(
  1003. Format,
  1004. arglist );
  1005. }
  1006. VOID
  1007. DnsDbg_Flush(
  1008. VOID
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. Flushes DNS debug printing to disk.
  1013. Arguments:
  1014. None
  1015. Return Value:
  1016. None.
  1017. --*/
  1018. {
  1019. //
  1020. // need to lock to protect handle as this maybe called
  1021. // 1) directly as this is exposed in dnslib.h
  1022. // 2) from hard ASSERT()
  1023. // and a print which wraps may be ongoing
  1024. //
  1025. if ( g_pDbgInfo->hFile )
  1026. {
  1027. HANDLE hfile;
  1028. DnsPrint_Lock();
  1029. if ( hfile = g_pDbgInfo->hFile )
  1030. {
  1031. FlushFileBuffers( hfile );
  1032. }
  1033. DnsPrint_Unlock();
  1034. }
  1035. }
  1036. VOID
  1037. DnsDbg_PrintfToDebugger(
  1038. IN LPSTR Format,
  1039. ...
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. Print to debugger. Win95 has no DbgPrint().
  1044. Arguments:
  1045. Format -- standard C format string
  1046. ... -- standard arg list
  1047. Return Value:
  1048. None.
  1049. --*/
  1050. {
  1051. va_list arglist;
  1052. CHAR outputBuffer[ DNS_STACK_PRINT_BUFFER_LENGTH+1 ];
  1053. ULONG length;
  1054. BOOL ret;
  1055. va_start( arglist, Format );
  1056. _vsnprintf( outputBuffer, DNS_STACK_PRINT_BUFFER_LENGTH, Format, arglist );
  1057. va_end( arglist );
  1058. outputBuffer[ DNS_STACK_PRINT_BUFFER_LENGTH ] = 0;
  1059. OutputDebugString( outputBuffer );
  1060. }
  1061. //
  1062. // Debug utilities
  1063. //
  1064. // Other debug routines are coded generically as print routines (print.c)
  1065. // and are macroed to debug routines by choosing DnsDbg_Printf() as the
  1066. // print function.
  1067. //
  1068. #if DBG
  1069. VOID
  1070. DnsDbg_CSEnter(
  1071. IN PCRITICAL_SECTION pLock,
  1072. IN LPSTR pszLockName,
  1073. IN LPSTR pszFile,
  1074. IN INT LineNo
  1075. )
  1076. {
  1077. DnsDbg_Printf(
  1078. "\nENTERING %s lock %p in %s, line %d.\n",
  1079. pszLockName,
  1080. pLock,
  1081. pszFile,
  1082. LineNo );
  1083. EnterCriticalSection( pLock );
  1084. DnsDbg_Printf(
  1085. "\nHOLDING %s lock %p in %s, line %d.\n",
  1086. pszLockName,
  1087. pLock,
  1088. pszFile,
  1089. LineNo );
  1090. }
  1091. VOID
  1092. DnsDbg_CSLeave(
  1093. IN PCRITICAL_SECTION pLock,
  1094. IN LPSTR pszLockName,
  1095. IN LPSTR pszFile,
  1096. IN INT LineNo
  1097. )
  1098. {
  1099. DnsDbg_Printf(
  1100. "\nRELEASING %s lock %p in %s, line %d.\n",
  1101. pszLockName,
  1102. pLock,
  1103. pszFile,
  1104. LineNo );
  1105. LeaveCriticalSection( pLock );
  1106. }
  1107. #endif
  1108. //
  1109. // End of debug.c
  1110. //