Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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