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.

763 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. Debug.c
  5. Abstract:
  6. This file contains routines to insulate more networking code from
  7. the actual NT debug routines.
  8. Author:
  9. John Rogers (JohnRo) 16-Apr-1991
  10. Environment:
  11. Interface is portable to any flat, 32-bit environment. (Uses Win32
  12. typedefs.) Requires ANSI C extensions: slash-slash comments, long
  13. external names. Code itself only runs under NT.
  14. Revision History:
  15. 16-Apr-1991 JohnRo
  16. Created. (Borrowed some code from LarryO's NetapipPrintf.)
  17. 19-May-1991 JohnRo
  18. Make LINT-suggested changes.
  19. 20-Aug-1991 JohnRo
  20. Another change suggested by PC-LINT.
  21. 17-Sep-1991 JohnRo
  22. Correct UNICODE use.
  23. 10-May-1992 JohnRo
  24. Correct a NetpDbgPrint bug when printing percent signs.
  25. --*/
  26. // These must be included first:
  27. #include <nt.h> // IN, LPVOID, etc.
  28. // These may be included in any order:
  29. #include <netdebug.h> // My prototypes.
  30. #include <nt.h>
  31. #include <ntrtl.h> // RtlAssert().
  32. #include <nturtl.h>
  33. #include <stdarg.h> // va_list, etc.
  34. #include <stdio.h> // vsprintf().
  35. #include <prefix.h> // PREFIX_ equates.
  36. #include <windows.h>
  37. //
  38. // Critical section used to control access to the log
  39. //
  40. RTL_CRITICAL_SECTION NetpLogCritSect;
  41. //
  42. // These routines are exported from netapi32.dll. We want them to still
  43. // be there in the free build, so checked binaries will run on a free
  44. // build. The following undef's are to get rid of the macros that cause
  45. // these to not be called in free builds.
  46. //
  47. #define DEBUG_DIR L"\\debug"
  48. #if !DBG
  49. #undef NetpAssertFailed
  50. #undef NetpHexDump
  51. #endif
  52. VOID
  53. NetpAssertFailed(
  54. IN LPDEBUG_STRING FailedAssertion,
  55. IN LPDEBUG_STRING FileName,
  56. IN DWORD LineNumber,
  57. IN LPDEBUG_STRING Message OPTIONAL
  58. )
  59. {
  60. #if DBG
  61. RtlAssert(
  62. FailedAssertion,
  63. FileName,
  64. (ULONG) LineNumber,
  65. (PCHAR) Message);
  66. #endif
  67. /* NOTREACHED */
  68. } // NetpAssertFailed
  69. #define MAX_PRINTF_LEN 1024 // Arbitrary.
  70. VOID
  71. NetpDbgPrint(
  72. IN LPDEBUG_STRING Format,
  73. ...
  74. )
  75. {
  76. va_list arglist;
  77. va_start(arglist, Format);
  78. vKdPrintEx((DPFLTR_NETAPI_ID, DPFLTR_INFO_LEVEL, Format, arglist));
  79. va_end(arglist);
  80. return;
  81. } // NetpDbgPrint
  82. VOID
  83. NetpHexDump(
  84. LPBYTE Buffer,
  85. DWORD BufferSize
  86. )
  87. /*++
  88. Routine Description:
  89. This function dumps the contents of the buffer to the debug screen.
  90. Arguments:
  91. Buffer - Supplies a pointer to the buffer that contains data to be dumped.
  92. BufferSize - Supplies the size of the buffer in number of bytes.
  93. Return Value:
  94. None.
  95. --*/
  96. {
  97. #define NUM_CHARS 16
  98. DWORD i, limit;
  99. TCHAR TextBuffer[NUM_CHARS + 1];
  100. //
  101. // Hex dump of the bytes
  102. //
  103. limit = ((BufferSize - 1) / NUM_CHARS + 1) * NUM_CHARS;
  104. for (i = 0; i < limit; i++) {
  105. if (i < BufferSize) {
  106. (VOID) DbgPrint("%02x ", Buffer[i]);
  107. if (Buffer[i] == TEXT('\r') ||
  108. Buffer[i] == TEXT('\n')) {
  109. TextBuffer[i % NUM_CHARS] = '.';
  110. }
  111. else if (Buffer[i] == '\0') {
  112. TextBuffer[i % NUM_CHARS] = ' ';
  113. }
  114. else {
  115. TextBuffer[i % NUM_CHARS] = (TCHAR) Buffer[i];
  116. }
  117. }
  118. else {
  119. (VOID) DbgPrint(" ");
  120. TextBuffer[i % NUM_CHARS] = ' ';
  121. }
  122. if ((i + 1) % NUM_CHARS == 0) {
  123. TextBuffer[NUM_CHARS] = 0;
  124. (VOID) DbgPrint(" %s \n", TextBuffer);
  125. }
  126. }
  127. (VOID) DbgPrint("\n");
  128. }
  129. #undef NetpBreakPoint
  130. VOID
  131. NetpBreakPoint(
  132. VOID
  133. )
  134. {
  135. #if DBG
  136. DbgBreakPoint();
  137. #endif
  138. } // NetpBreakPoint
  139. //
  140. // NOTICE
  141. // The debug log code was blatantly stolen from net\svcdlls\netlogon\server\nlp.c
  142. //
  143. //
  144. // Generalized logging support is provided below. The proper calling procedure is:
  145. //
  146. // NetpInitializeLogFile() - Call this once per process/log lifespan
  147. // NetpOpenDebugFile() - Call this to open a log file instance
  148. // NetpDebugDumpRoutine() / NetpLogPrintRoutine() - Call this every time you wish to
  149. // write data to the log. This can be done. Mutli-threaded safe.
  150. // NetpCloseDebugFile() - Call this to close a log instance
  151. // NetpShutdownLogFile() - Call this once per process/log lifespan
  152. //
  153. // NetpResetLog() - This support routine is provided to reset a log file pointer to
  154. // the end of the file. Usefull if the log is being shared.
  155. //
  156. //
  157. // Notes: NetpInitializeLogFile need only be called once per logging process instance,
  158. // meaning that a given logging process (such as netlogon, which does not exist as
  159. // a separate NT process, but does logging from multiple threads within a NT process).
  160. // Likewise, it would only call NetpShutdownLogFile once. This logging process can then
  161. // open and close the debug log as many times as it desires. Or, if there is only going
  162. // to be one instance of a log operating at any given moment, the Initialize and Shutdown
  163. // calls can wrap the Open and Close calls.
  164. //
  165. // The CloseDebugFile does a flush before closing the handle
  166. //
  167. VOID
  168. NetpInitializeLogFile(
  169. VOID
  170. )
  171. /*++
  172. Routine Description:
  173. Initializes the process for logging
  174. Arguments:
  175. None
  176. Return Value:
  177. None
  178. --*/
  179. {
  180. InitializeCriticalSection( &NetpLogCritSect );
  181. }
  182. VOID
  183. NetpShutdownLogFile(
  184. VOID
  185. )
  186. /*++
  187. Routine Description:
  188. The opposite of the former function
  189. Arguments:
  190. None
  191. Return Value:
  192. None
  193. --*/
  194. {
  195. DeleteCriticalSection( &NetpLogCritSect );
  196. }
  197. HANDLE
  198. NetpOpenDebugFile(
  199. IN LPWSTR DebugLog,
  200. IN BOOLEAN ReopenFlag
  201. )
  202. /*++
  203. Routine Description:
  204. Opens or re-opens the debug file
  205. This code blatantly stolen from net\svcdlls\netlogon\server\nlp.c
  206. Arguments:
  207. ReopenFlag - TRUE to indicate the debug file is to be closed, renamed,
  208. and recreated.
  209. DebugLog - Root name of the debug log. The given name will have a .LOG appeneded to it
  210. Return Value:
  211. None
  212. --*/
  213. {
  214. WCHAR LogFileName[MAX_PATH+1];
  215. WCHAR BakFileName[MAX_PATH+1];
  216. DWORD FileAttributes;
  217. DWORD PathLength, LogLen;
  218. DWORD WinError;
  219. HANDLE DebugLogHandle = NULL;
  220. //
  221. // make debug directory path first, if it is not made before.
  222. //
  223. if ( !GetWindowsDirectoryW(
  224. LogFileName,
  225. sizeof(LogFileName)/sizeof(WCHAR) ) ) {
  226. NetpKdPrint((PREFIX_NETLIB "Window Directory Path can't be retrieved, %lu.\n",
  227. GetLastError() ));
  228. return( DebugLogHandle );
  229. }
  230. //
  231. // check debug path length.
  232. //
  233. LogLen = 1 + wcslen( DebugLog ) + 4; // 1 is for the \\ and 4 is for the .LOG or .BAK
  234. PathLength = wcslen(LogFileName) * sizeof(WCHAR) +
  235. sizeof(DEBUG_DIR) + sizeof(WCHAR);
  236. if( (PathLength + ( ( LogLen + 1 ) * sizeof(WCHAR) ) > sizeof(LogFileName) ) ||
  237. (PathLength + ( ( LogLen + 1 ) * sizeof(WCHAR) ) > sizeof(BakFileName) ) ) {
  238. NetpKdPrint((PREFIX_NETLIB "Debug directory path (%ws) length is too long.\n",
  239. LogFileName));
  240. goto ErrorReturn;
  241. }
  242. wcscat(LogFileName, DEBUG_DIR);
  243. //
  244. // Check this path exists.
  245. //
  246. FileAttributes = GetFileAttributesW( LogFileName );
  247. if( FileAttributes == 0xFFFFFFFF ) {
  248. WinError = GetLastError();
  249. if( WinError == ERROR_FILE_NOT_FOUND ) {
  250. //
  251. // Create debug directory.
  252. //
  253. if( !CreateDirectoryW( LogFileName, NULL) ) {
  254. NetpKdPrint((PREFIX_NETLIB "Can't create Debug directory (%ws), %lu.\n",
  255. LogFileName, GetLastError() ));
  256. goto ErrorReturn;
  257. }
  258. }
  259. else {
  260. NetpKdPrint((PREFIX_NETLIB "Can't Get File attributes(%ws), %lu.\n",
  261. LogFileName, WinError ));
  262. goto ErrorReturn;
  263. }
  264. }
  265. else {
  266. //
  267. // if this is not a directory.
  268. //
  269. if(!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  270. NetpKdPrint((PREFIX_NETLIB "Debug directory path (%ws) exists as file.\n",
  271. LogFileName));
  272. goto ErrorReturn;
  273. }
  274. }
  275. //
  276. // Create the name of the old and new log file names
  277. //
  278. swprintf( BakFileName, L"%ws\\%ws.BAK", LogFileName, DebugLog );
  279. (VOID) wcscat( LogFileName, L"\\" );
  280. (VOID) wcscat( LogFileName, DebugLog );
  281. (VOID) wcscat( LogFileName, L".LOG" );
  282. //
  283. // If this is a re-open,
  284. // delete the backup file,
  285. // rename the current file to the backup file.
  286. //
  287. if ( ReopenFlag ) {
  288. if ( !DeleteFile( BakFileName ) ) {
  289. WinError = GetLastError();
  290. if ( WinError != ERROR_FILE_NOT_FOUND ) {
  291. NetpKdPrint((PREFIX_NETLIB "Cannot delete %ws (%ld)\n",
  292. BakFileName,
  293. WinError ));
  294. NetpKdPrint((PREFIX_NETLIB " Try to re-open the file.\n"));
  295. ReopenFlag = FALSE; // Don't truncate the file
  296. }
  297. }
  298. }
  299. if ( ReopenFlag ) {
  300. if ( !MoveFile( LogFileName, BakFileName ) ) {
  301. NetpKdPrint((PREFIX_NETLIB "Cannot rename %ws to %ws (%ld)\n",
  302. LogFileName,
  303. BakFileName,
  304. GetLastError() ));
  305. NetpKdPrint((PREFIX_NETLIB " Try to re-open the file.\n"));
  306. ReopenFlag = FALSE; // Don't truncate the file
  307. }
  308. }
  309. //
  310. // Open the file.
  311. //
  312. DebugLogHandle = CreateFileW( LogFileName,
  313. GENERIC_WRITE,
  314. FILE_SHARE_READ | FILE_SHARE_WRITE,
  315. NULL,
  316. ReopenFlag ? CREATE_ALWAYS : OPEN_ALWAYS,
  317. FILE_ATTRIBUTE_NORMAL,
  318. NULL );
  319. if ( DebugLogHandle == INVALID_HANDLE_VALUE ) {
  320. DebugLogHandle = NULL;
  321. NetpKdPrint((PREFIX_NETLIB "cannot open %ws \n",
  322. LogFileName ));
  323. goto ErrorReturn;
  324. } else {
  325. // Position the log file at the end
  326. (VOID) SetFilePointer( DebugLogHandle,
  327. 0,
  328. NULL,
  329. FILE_END );
  330. }
  331. return( DebugLogHandle );;
  332. ErrorReturn:
  333. NetpKdPrint((PREFIX_NETLIB " Debug output will be written to debug terminal.\n"));
  334. return( DebugLogHandle );
  335. }
  336. VOID
  337. NetpDebugDumpRoutine(
  338. IN HANDLE LogHandle,
  339. IN PDWORD OpenLogThreadId OPTIONAL,
  340. IN LPSTR Format,
  341. va_list arglist
  342. )
  343. /*++
  344. Routine Description:
  345. Writes a formatted output string to the debug log
  346. Arguments:
  347. LogHandle -- Handle to the open log
  348. OpenLogThreadId -- The ID of the thread (obtained from
  349. GetCurrentThreadId) that explicitly opened the log.
  350. If not equal to the current thread ID, the current
  351. thread ID will be output in the log.
  352. Format -- printf style format string
  353. arglist -- List of arguments to dump
  354. Return Value:
  355. None
  356. --*/
  357. {
  358. char OutputBuffer[2049];
  359. ULONG length;
  360. DWORD BytesWritten;
  361. SYSTEMTIME SystemTime;
  362. static BeginningOfLine = TRUE;
  363. //
  364. // If we don't have an open log file, just bail
  365. //
  366. if ( LogHandle == NULL ) {
  367. return;
  368. }
  369. EnterCriticalSection( &NetpLogCritSect );
  370. length = 0;
  371. //
  372. // Handle the beginning of a new line.
  373. //
  374. //
  375. if ( BeginningOfLine ) {
  376. //
  377. // Put the timestamp at the begining of the line.
  378. //
  379. GetLocalTime( &SystemTime );
  380. length += (ULONG) sprintf( &OutputBuffer[length],
  381. "%02u/%02u %02u:%02u:%02u ",
  382. SystemTime.wMonth,
  383. SystemTime.wDay,
  384. SystemTime.wHour,
  385. SystemTime.wMinute,
  386. SystemTime.wSecond );
  387. //
  388. // If the current thread is not the one which opened
  389. // the log, output the current thread ID
  390. //
  391. if ( OpenLogThreadId != NULL ) {
  392. DWORD CurrentThreadId = GetCurrentThreadId();
  393. if ( CurrentThreadId != *OpenLogThreadId ) {
  394. length += sprintf(&OutputBuffer[length], "[%08lx] ", CurrentThreadId);
  395. }
  396. }
  397. }
  398. //
  399. // Put the information requested by the caller onto the line
  400. //
  401. length += (ULONG) vsprintf(&OutputBuffer[length], Format, arglist);
  402. BeginningOfLine = (length > 0 && OutputBuffer[length-1] == '\n' );
  403. if ( BeginningOfLine ) {
  404. OutputBuffer[length-1] = '\r';
  405. OutputBuffer[length] = '\n';
  406. OutputBuffer[length+1] = '\0';
  407. length++;
  408. }
  409. ASSERT( length <= sizeof( OutputBuffer ) / sizeof( CHAR ) );
  410. //
  411. // Write the debug info to the log file.
  412. //
  413. if ( LogHandle ) {
  414. if ( !WriteFile( LogHandle,
  415. OutputBuffer,
  416. length,
  417. &BytesWritten,
  418. NULL ) ) {
  419. NetpKdPrint((PREFIX_NETLIB "Log write of %s failed with %lu\n",
  420. OutputBuffer,
  421. GetLastError() ));
  422. }
  423. } else {
  424. NetpKdPrint((PREFIX_NETLIB "[LOGWRITE]%s\n", OutputBuffer));
  425. }
  426. LeaveCriticalSection( &NetpLogCritSect );
  427. }
  428. VOID
  429. NetpLogPrintRoutine(
  430. IN HANDLE LogHandle,
  431. IN LPSTR Format,
  432. ...
  433. )
  434. /*++
  435. Routine Description:
  436. Writes a formatted output string to the debug log
  437. Arguments:
  438. LogHandle -- Handle to the open log
  439. Format -- printf style format string
  440. ... -- List of arguments to dump
  441. Return Value:
  442. None
  443. --*/
  444. {
  445. va_list arglist;
  446. if ( !LogHandle )
  447. {
  448. return;
  449. }
  450. va_start(arglist, Format);
  451. NetpLogPrintRoutineV(LogHandle, Format, arglist);
  452. va_end(arglist);
  453. }
  454. VOID
  455. NetpLogPrintRoutineVEx(
  456. IN HANDLE LogHandle,
  457. IN PDWORD OpenLogThreadId OPTIONAL,
  458. IN LPSTR Format,
  459. IN va_list arglist
  460. )
  461. /*++
  462. Routine Description:
  463. Writes a formatted output string to the debug log
  464. Arguments:
  465. LogHandle -- Handle to the open log
  466. OpenLogThreadId -- The ID of the thread (obtained from
  467. GetCurrentThreadId) that explicitly opened the log.
  468. If not equal to the current thread ID, the current
  469. thread ID will be output in the log.
  470. Format -- printf style format string
  471. arglist -- List of arguments to dump
  472. Return Value:
  473. None
  474. --*/
  475. {
  476. if ( !LogHandle )
  477. {
  478. return;
  479. }
  480. EnterCriticalSection( &NetpLogCritSect );
  481. NetpDebugDumpRoutine( LogHandle, OpenLogThreadId, Format, arglist );
  482. LeaveCriticalSection( &NetpLogCritSect );
  483. }
  484. VOID
  485. NetpLogPrintRoutineV(
  486. IN HANDLE LogHandle,
  487. IN LPSTR Format,
  488. IN va_list arglist
  489. )
  490. /*++
  491. Routine Description:
  492. Writes a formatted output string to the debug log
  493. Arguments:
  494. LogHandle -- Handle to the open log
  495. Format -- printf style format string
  496. arglist -- List of arguments to dump
  497. Return Value:
  498. None
  499. --*/
  500. {
  501. NetpLogPrintRoutineVEx( LogHandle, NULL, Format, arglist );
  502. }
  503. VOID
  504. NetpResetLog(
  505. IN HANDLE LogHandle
  506. )
  507. /*++
  508. Routine Description:
  509. Seeks to the end of the log file
  510. Arguments:
  511. LogHandle -- Handle to the open log
  512. Returns:
  513. ERROR_SUCCESS - Success
  514. --*/
  515. {
  516. if ( LogHandle ) {
  517. if( SetFilePointer( LogHandle,
  518. 0, 0,
  519. FILE_END ) == 0xFFFFFFFF ) {
  520. NetpKdPrint((PREFIX_NETLIB "Seek to end of debug log failed with %lu\n",
  521. GetLastError() ));
  522. }
  523. }
  524. return;
  525. }
  526. VOID
  527. NetpCloseDebugFile(
  528. IN HANDLE LogHandle
  529. )
  530. /*++
  531. Routine Description:
  532. Closes the output log
  533. Arguments:
  534. LogHandle -- Handle to the open log
  535. Return Value:
  536. None
  537. --*/
  538. {
  539. if ( LogHandle ) {
  540. if( FlushFileBuffers( LogHandle ) == FALSE ) {
  541. NetpKdPrint((PREFIX_NETLIB "Flush of debug log failed with %lu\n",
  542. GetLastError() ));
  543. }
  544. CloseHandle( LogHandle );
  545. }
  546. }