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.

1710 lines
41 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: debug.c
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 3-14-95 RichardW Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "debuglib.h"
  18. SECURITY_DESCRIPTOR DbgpPartySd;
  19. BOOL DbgpPartySdInit = FALSE;
  20. PDebugHeader DbgpHeader = NULL;
  21. DebugModule * * DbgpFixupModules[] = { &__pAssertModule,
  22. &__pExceptionModule,
  23. NULL };
  24. CHAR szDebugSection[] = "DSysDebug";
  25. CHAR szDebugFlags[] = "DebugFlags";
  26. DEBUG_KEY DbgpKeys[] = { {DEBUG_NO_DEBUGIO, "NoDebugger"},
  27. {DEBUG_TIMESTAMP, "TimeStamp"},
  28. {DEBUG_DEBUGGER_OK, "DebuggerOk"},
  29. {DEBUG_LOGFILE, "Logfile"},
  30. {DEBUG_AUTO_DEBUG, "AutoDebug"},
  31. {DEBUG_USE_KDEBUG, "UseKD"},
  32. {DEBUG_HEAP_CHECK, "HeapCheck"},
  33. {DEBUG_MULTI_THREAD, "MultiThread"},
  34. {DEBUG_DISABLE_ASRT, "DisableAssert"},
  35. {DEBUG_PROMPTS, "AssertPrompts"},
  36. {DEBUG_BREAK_ON_ERROR,"BreakOnError"},
  37. {0, NULL }
  38. };
  39. #define DEBUG_NUMBER_OF_KEYS ((sizeof(DbgpKeys) / sizeof(DEBUG_KEY)) - 1)
  40. #define _ALIGN(x,a) (x & (a-1) ? (x + a) & ~(a - 1) : x);
  41. #define ALIGN_8(x) _ALIGN(x, 8)
  42. #define ALIGN_16(x) _ALIGN(x, 16)
  43. #ifdef WIN64
  44. #define DBG_ALIGN ALIGN_16
  45. #else
  46. #define DBG_ALIGN ALIGN_8
  47. #endif
  48. #define DEBUGMEM_ALLOCATED 0x00000001
  49. typedef struct _DebugMemory {
  50. struct _DebugMemory * pNext;
  51. DWORD Size;
  52. DWORD Flags;
  53. } DebugMemory, * PDebugMemory;
  54. #ifdef DEBUG_DEBUG
  55. #define LockDebugHeader(p) EnterCriticalSection(&((p)->csDebug)); OutputDebugStringA("Lock")
  56. #define UnlockDebugHeader(p) LeaveCriticalSection(&((p)->csDebug)); OutputDebugStringA("Unlock")
  57. #else
  58. #define LockDebugHeader(p) EnterCriticalSection(&((p)->csDebug))
  59. #define UnlockDebugHeader(p) LeaveCriticalSection(&((p)->csDebug))
  60. #endif
  61. //+---------------------------------------------------------------------------
  62. //
  63. // Function: DbgpComputeMappingName
  64. //
  65. // Synopsis: Computes the mapping object name
  66. //
  67. // Arguments: [pszName] -- place to stick the name (no more than 32 wchars)
  68. //
  69. // History: 3-22-95 RichardW Created
  70. //
  71. // Notes:
  72. //
  73. //----------------------------------------------------------------------------
  74. void
  75. DbgpComputeMappingName(PWSTR pszName)
  76. {
  77. swprintf(pszName, TEXT("Debug.Memory.%x"), GetCurrentProcessId());
  78. }
  79. //+---------------------------------------------------------------------------
  80. //
  81. // Function: DbgpInitializeMM
  82. //
  83. // Synopsis: Initializes our simple memory manager within the shared mem
  84. // section.
  85. //
  86. // Arguments: [pHeader] -- Header to initialize
  87. //
  88. // History: 3-22-95 RichardW Created
  89. //
  90. // Notes:
  91. //
  92. //----------------------------------------------------------------------------
  93. VOID
  94. DbgpInitializeMM(PDebugHeader pHeader)
  95. {
  96. PDebugMemory pMem;
  97. pMem = (PDebugMemory) (pHeader + 1);
  98. pMem->pNext = NULL;
  99. pMem->Size = pHeader->CommitRange - (sizeof(DebugHeader) + sizeof(DebugMemory));
  100. pHeader->pFreeList = pMem;
  101. }
  102. //+---------------------------------------------------------------------------
  103. //
  104. // Function: DbgpAlloc
  105. //
  106. // Synopsis: Very, very simple allocator
  107. //
  108. // Arguments: [pHeader] -- Header from which to allocate
  109. // [cSize] -- size to allocate
  110. //
  111. // History: 3-22-95 RichardW Created
  112. //
  113. // Notes:
  114. //
  115. //----------------------------------------------------------------------------
  116. PVOID
  117. DbgpAlloc(
  118. PDebugHeader pHeader,
  119. DWORD cSize)
  120. {
  121. PDebugMemory pSearch;
  122. PDebugMemory pLargest = NULL;
  123. PDebugMemory pNew;
  124. DWORD cLargest;
  125. cLargest = 0;
  126. cSize = DBG_ALIGN(cSize);
  127. //
  128. // Very, very simple allocator. Search free list for an exact match,
  129. //
  130. pSearch = (PDebugMemory) pHeader->pFreeList;
  131. while (pSearch)
  132. {
  133. if ( ( pSearch->Flags & DEBUGMEM_ALLOCATED ) == 0 )
  134. {
  135. if ( pSearch->Size == cSize )
  136. {
  137. break;
  138. }
  139. if (pSearch->Size > cLargest)
  140. {
  141. pLargest = pSearch;
  142. cLargest = pSearch->Size;
  143. }
  144. }
  145. pSearch = pSearch->pNext;
  146. }
  147. //
  148. // If no match yet
  149. //
  150. if (!pSearch)
  151. {
  152. //
  153. // If the largest free block is still too small,
  154. //
  155. if (cLargest < (cSize + sizeof(DebugMemory) * 2))
  156. {
  157. //
  158. // Extend the mapped range
  159. //
  160. if (pHeader->CommitRange < pHeader->ReserveRange)
  161. {
  162. if ( VirtualAlloc(
  163. (PUCHAR) pHeader + pHeader->CommitRange,
  164. pHeader->PageSize,
  165. MEM_COMMIT,
  166. PAGE_READWRITE ) )
  167. {
  168. pNew = (PDebugMemory) ((PUCHAR) pHeader + pHeader->CommitRange );
  169. pHeader->CommitRange += pHeader->PageSize ;
  170. pNew->Size = pHeader->PageSize - sizeof( DebugMemory );
  171. pNew->pNext = pHeader->pFreeList ;
  172. pHeader->pFreeList = pNew ;
  173. return DbgpAlloc( pHeader, cSize );
  174. }
  175. else
  176. {
  177. return NULL ;
  178. }
  179. }
  180. return(NULL);
  181. }
  182. //
  183. // Otherwise, split the largest block into something better...
  184. //
  185. pNew = (PDebugMemory) ((PUCHAR) pLargest + (cSize + sizeof(DebugMemory)) );
  186. pNew->Size = pLargest->Size - (cSize + sizeof(DebugMemory) * 2);
  187. pNew->pNext = pLargest->pNext ;
  188. pNew->Flags = 0;
  189. pLargest->Size = cSize;
  190. pLargest->Flags |= DEBUGMEM_ALLOCATED;
  191. pLargest->pNext = pNew;
  192. return((PVOID) (pLargest + 1) );
  193. }
  194. else
  195. {
  196. pSearch->Flags |= DEBUGMEM_ALLOCATED ;
  197. return((PVOID) (pSearch + 1) );
  198. }
  199. return(NULL);
  200. }
  201. //+---------------------------------------------------------------------------
  202. //
  203. // Function: DbgpFree
  204. //
  205. // Synopsis: Returns memory to the shared mem segment
  206. //
  207. // Arguments: [pHeader] -- Shared memory header
  208. // [pMemory] -- Memory to free
  209. //
  210. // History: 3-22-95 RichardW Created
  211. //
  212. // Notes: No compaction.
  213. //
  214. //----------------------------------------------------------------------------
  215. VOID
  216. DbgpFree(
  217. PDebugHeader pHeader,
  218. PVOID pMemory)
  219. {
  220. PDebugMemory pMem;
  221. pMem = (PDebugMemory) ((PUCHAR) pMemory - sizeof(DebugMemory));
  222. pMem->Flags &= ~DEBUGMEM_ALLOCATED;
  223. ZeroMemory( pMemory, pMem->Size );
  224. }
  225. //+---------------------------------------------------------------------------
  226. //
  227. // Function: DbgpFindModule
  228. //
  229. // Synopsis: Locates a module based on a name
  230. //
  231. // Arguments: [pHeader] -- Header to search
  232. // [pszName] -- module to find
  233. //
  234. // History: 3-22-95 RichardW Created
  235. //
  236. // Notes:
  237. //
  238. //----------------------------------------------------------------------------
  239. PDebugModule
  240. DbgpFindModule(
  241. PDebugHeader pHeader,
  242. CHAR * pszName)
  243. {
  244. PDebugModule pSearch;
  245. pSearch = pHeader->pModules;
  246. while (pSearch)
  247. {
  248. if (_strcmpi(pSearch->pModuleName, pszName) == 0)
  249. {
  250. return(pSearch);
  251. }
  252. pSearch = pSearch->pNext;
  253. }
  254. return(NULL);
  255. }
  256. //+---------------------------------------------------------------------------
  257. //
  258. // Function: DbgpCopyModule
  259. //
  260. // Synopsis: Copies a module into a new module. Used for the builtins.
  261. // note, no references to the code module that the builtin lived
  262. // in is kept. This way, the module can unload.
  263. //
  264. // Arguments: [pHeader] --
  265. // [pSource] --
  266. // [ppDest] --
  267. //
  268. // Requires: Header must be locked.
  269. //
  270. // Returns: 0 for failure, non-zero for success
  271. //
  272. // History: 7-19-95 RichardW Created
  273. //
  274. // Notes:
  275. //
  276. //----------------------------------------------------------------------------
  277. DWORD
  278. DbgpCopyModule(
  279. PDebugHeader pHeader,
  280. PDebugModule pSource,
  281. PDebugModule * ppDest)
  282. {
  283. PDebugModule pModule;
  284. DWORD i;
  285. DWORD cStringSpace;
  286. PCHAR pStrings;
  287. *ppDest = NULL;
  288. cStringSpace = strlen(pSource->pModuleName) + 1;
  289. for (i = 0; i < 32 ; i++ )
  290. {
  291. if (pSource->TagLevels[i])
  292. {
  293. cStringSpace += (strlen(pSource->TagLevels[i]) + 1);
  294. }
  295. }
  296. //
  297. // Allocate an extra DWORD to store the infolevel.
  298. //
  299. pModule = DbgpAlloc(pHeader, sizeof(DebugModule) + sizeof( DWORD ) );
  300. if (!pModule)
  301. {
  302. return(0);
  303. }
  304. pStrings = DbgpAlloc(pHeader, cStringSpace);
  305. if ( !pStrings )
  306. {
  307. DbgpFree( pHeader, pModule );
  308. return 0 ;
  309. }
  310. pModule->pModuleName = pStrings;
  311. cStringSpace = strlen(pSource->pModuleName) + 1;
  312. strcpy(pModule->pModuleName, pSource->pModuleName);
  313. pStrings += cStringSpace;
  314. for (i = 0; i < 32 ; i++ )
  315. {
  316. if (pSource->TagLevels[i])
  317. {
  318. pModule->TagLevels[i] = pStrings;
  319. cStringSpace = strlen(pSource->TagLevels[i]) + 1;
  320. strcpy(pStrings, pSource->TagLevels[i]);
  321. pStrings += cStringSpace;
  322. }
  323. else
  324. {
  325. pSource->TagLevels[i] = NULL;
  326. }
  327. }
  328. //
  329. // Add this in to the global list
  330. //
  331. pModule->pNext = pHeader->pModules;
  332. pHeader->pModules = pModule;
  333. //
  334. // Do not increment module count - this is a builtin
  335. //
  336. //
  337. // Copy the rest of the interesting stuff
  338. //
  339. pModule->pInfoLevel = (PDWORD) (pModule + 1);
  340. *pModule->pInfoLevel = *pSource->pInfoLevel;
  341. pModule->InfoLevel = pSource->InfoLevel;
  342. pModule->fModule = pSource->fModule | DEBUGMOD_BUILTIN_MODULE ;
  343. pModule->pHeader = pHeader;
  344. pModule->TotalOutput = pSource->TotalOutput;
  345. pModule->Reserved = 0;
  346. *ppDest = pModule;
  347. return(1);
  348. }
  349. //+---------------------------------------------------------------------------
  350. //
  351. // Function: DbgpAttachBuiltinModules
  352. //
  353. // Synopsis: Attaches the builtin library modules to the global shared
  354. // list
  355. //
  356. // Arguments: [pHeader] --
  357. //
  358. // History: 7-19-95 RichardW Created
  359. //
  360. // Notes:
  361. //
  362. //----------------------------------------------------------------------------
  363. BOOL
  364. DbgpAttachBuiltinModules(
  365. PDebugHeader pHeader)
  366. {
  367. PDebugModule pModule;
  368. PDebugModule pFixup;
  369. DWORD i;
  370. BOOL Success = FALSE;
  371. i = 0;
  372. while (DbgpFixupModules[i])
  373. {
  374. pFixup = *DbgpFixupModules[i];
  375. pModule = DbgpFindModule(pHeader, pFixup->pModuleName);
  376. if (pModule)
  377. {
  378. *DbgpFixupModules[i] = pModule;
  379. Success = TRUE;
  380. }
  381. else
  382. {
  383. if (DbgpCopyModule(pHeader, pFixup, &pModule))
  384. {
  385. *DbgpFixupModules[i] = pModule;
  386. Success = TRUE;
  387. }
  388. }
  389. i++;
  390. }
  391. return(Success);
  392. }
  393. //+---------------------------------------------------------------------------
  394. //
  395. // Function: DbgpBuildModule
  396. //
  397. // Synopsis: Initializes a Module, builds the string table
  398. //
  399. // Arguments: [pModule] -- Module pointer
  400. // [pHeader] -- Header
  401. // [pKeys] -- Key table
  402. // [pszName] -- Name
  403. // [pInfoLevel] -- Pointer to info level
  404. //
  405. // History: 4-03-95 RichardW Created
  406. //
  407. // Notes:
  408. //
  409. //----------------------------------------------------------------------------
  410. DWORD
  411. DbgpBuildModule(
  412. PDebugModule pModule,
  413. PDebugHeader pHeader,
  414. PDEBUG_KEY pKeys,
  415. PCHAR pszName,
  416. PDWORD pInfoLevel)
  417. {
  418. PCHAR pStringData;
  419. DWORD cStringData;
  420. DWORD cKeys;
  421. DWORD i;
  422. DWORD KeyIndex;
  423. DWORD BitScan;
  424. //
  425. // Easy stuff to start..
  426. //
  427. pModule->pInfoLevel = pInfoLevel;
  428. pModule->pHeader = pHeader;
  429. cStringData = strlen(pszName) + 1;
  430. //
  431. // Search through the list of masks and string tags, computing
  432. // the size needed for containing them all. If a tag has more
  433. // than one bit set, reject it.
  434. //
  435. for (i = 0; i < 32 ; i++ )
  436. {
  437. if (pKeys[i].Mask)
  438. {
  439. if (pKeys[i].Mask & (pKeys[i].Mask - 1))
  440. {
  441. continue;
  442. }
  443. }
  444. if (pKeys[i].Tag)
  445. {
  446. cStringData += strlen(pKeys[i].Tag) + 1;
  447. }
  448. else
  449. {
  450. break;
  451. }
  452. }
  453. //
  454. // We know how many keys there are, and how big a space they need.
  455. //
  456. cKeys = i;
  457. pStringData = DbgpAlloc(pHeader, cStringData);
  458. if ( !pStringData )
  459. {
  460. return 0 ;
  461. }
  462. pModule->pModuleName = pStringData;
  463. strcpy(pStringData, pszName);
  464. pStringData += strlen(pStringData) + 1;
  465. for (i = 0, KeyIndex = 0; i < cKeys ; i++ )
  466. {
  467. if (pKeys[i].Mask & (pKeys[i].Mask - 1))
  468. {
  469. continue;
  470. }
  471. if (!(pKeys[i].Mask & (1 << KeyIndex)))
  472. {
  473. //
  474. // Grr, out of order. Do a bit-wise scan.
  475. //
  476. KeyIndex = 0;
  477. BitScan = 1;
  478. while ((pKeys[i].Mask & BitScan) == 0)
  479. {
  480. BitScan <<= 1;
  481. KeyIndex ++;
  482. }
  483. }
  484. pModule->TagLevels[KeyIndex] = pStringData;
  485. strcpy(pStringData, pKeys[i].Tag);
  486. pStringData += strlen(pKeys[i].Tag) + 1;
  487. KeyIndex++;
  488. }
  489. return(cKeys);
  490. }
  491. //+---------------------------------------------------------------------------
  492. //
  493. // Function: DbgpGetBitmask
  494. //
  495. // Synopsis: Based on a parameter line and a key table, builds the bitmask
  496. //
  497. // Arguments: [pKeys] --
  498. // [cKeys] --
  499. // [pszLine] --
  500. // [ParameterIndex] --
  501. // [ParameterValue] --
  502. //
  503. // History: 4-03-95 RichardW Created
  504. //
  505. // Notes:
  506. //
  507. //----------------------------------------------------------------------------
  508. DWORD
  509. DbgpGetBitmask(
  510. DEBUG_KEY * pKeys,
  511. DWORD cKeys,
  512. PCHAR pszLine,
  513. DWORD ParameterIndex,
  514. PCHAR ParameterValue)
  515. {
  516. PCHAR pszSearch;
  517. PCHAR pszParam;
  518. PCHAR pszScan;
  519. DWORD i;
  520. DWORD Mask;
  521. DWORD cbParameter = 0;
  522. DWORD Compare;
  523. CHAR Saved;
  524. if (ParameterIndex < cKeys)
  525. {
  526. cbParameter = strlen(pKeys[ParameterIndex].Tag);
  527. }
  528. Mask = 0;
  529. pszSearch = pszLine;
  530. //
  531. // Scan through the line, searching for flags. Note: do NOT use strtok,
  532. // since that is not exported by ntdll, and we would not be able to make
  533. // security.dll
  534. //
  535. while (*pszSearch)
  536. {
  537. pszScan = pszSearch;
  538. while ((*pszScan) && (*pszScan != ','))
  539. {
  540. pszScan++;
  541. }
  542. Saved = *pszScan;
  543. *pszScan = '\0';
  544. for (i = 0; i < cKeys ; i++ )
  545. {
  546. if (i == ParameterIndex)
  547. {
  548. if (_strnicmp(pKeys[i].Tag, pszSearch, cbParameter) == 0)
  549. {
  550. pszParam = strchr(pszSearch, ':');
  551. if (pszParam)
  552. {
  553. strcpy(ParameterValue, pszParam+1);
  554. }
  555. Mask |= pKeys[i].Mask;
  556. }
  557. }
  558. else
  559. {
  560. if (_strcmpi(pKeys[i].Tag, pszSearch) == 0)
  561. {
  562. Mask |= pKeys[i].Mask;
  563. }
  564. }
  565. }
  566. *pszScan = Saved;
  567. if (Saved)
  568. {
  569. while ((*pszScan) && ((*pszScan == ',') || (*pszScan == ' ')))
  570. {
  571. pszScan++;
  572. }
  573. }
  574. pszSearch = pszScan;
  575. }
  576. return(Mask);
  577. }
  578. //+---------------------------------------------------------------------------
  579. //
  580. // Function: DbgpInitializeDebug
  581. //
  582. // Synopsis: Initialize the base memory
  583. //
  584. // Arguments: [pHeader] --
  585. //
  586. // History: 4-03-95 RichardW Created
  587. //
  588. // Notes:
  589. //
  590. //----------------------------------------------------------------------------
  591. VOID
  592. DbgpInitializeDebug(
  593. PDebugHeader pHeader)
  594. {
  595. CHAR szExeName[MAX_PATH];
  596. PCHAR pszExeName;
  597. PCHAR dot;
  598. DWORD cbExeName;
  599. CHAR LogFile[MAX_PATH];
  600. CHAR Line[MAX_PATH];
  601. SECURITY_ATTRIBUTES sa;
  602. PDebugModule pModule;
  603. HANDLE Token ;
  604. TOKEN_STATISTICS TokenStat ;
  605. ULONG Size ;
  606. LUID LocalSys = SYSTEM_LUID ;
  607. //
  608. // Plug the debug section in first
  609. //
  610. pModule = DbgpAlloc(pHeader, sizeof(DebugModule));
  611. if (!pModule)
  612. {
  613. return;
  614. }
  615. DbgpBuildModule(pModule,
  616. pHeader,
  617. DbgpKeys,
  618. DEBUG_MODULE_NAME,
  619. &pHeader->fDebug);
  620. GetModuleFileNameA(NULL, szExeName, MAX_PATH);
  621. pszExeName = strrchr(szExeName, '\\');
  622. if (pszExeName)
  623. {
  624. pszExeName++;
  625. }
  626. else
  627. {
  628. pszExeName = szExeName;
  629. }
  630. dot = strrchr(pszExeName, '.');
  631. if (dot)
  632. {
  633. *dot = '\0';
  634. }
  635. cbExeName = (DWORD) (dot - pszExeName);
  636. pHeader->pszExeName = DbgpAlloc(pHeader, cbExeName + 1);
  637. if (pHeader->pszExeName)
  638. {
  639. strcpy(pHeader->pszExeName, pszExeName);
  640. }
  641. LogFile[0] = '\0';
  642. if (GetProfileStringA( szDebugSection,
  643. pszExeName,
  644. "",
  645. Line,
  646. MAX_PATH))
  647. {
  648. pHeader->fDebug = DbgpGetBitmask( DbgpKeys,
  649. DEBUG_NUMBER_OF_KEYS,
  650. Line,
  651. 3,
  652. LogFile);
  653. }
  654. //
  655. // If running as local system, turn on the kd flag. That
  656. // way,
  657. if ( OpenProcessToken( GetCurrentProcess(),
  658. TOKEN_QUERY,
  659. &Token ) )
  660. {
  661. if ( GetTokenInformation( Token,
  662. TokenStatistics,
  663. &TokenStat,
  664. sizeof( TokenStat ),
  665. &Size ) )
  666. {
  667. if ( (TokenStat.AuthenticationId.LowPart == LocalSys.LowPart ) &&
  668. (TokenStat.AuthenticationId.HighPart == LocalSys.HighPart ) )
  669. {
  670. pHeader->fDebug |= DEBUG_USE_KDEBUG ;
  671. }
  672. }
  673. CloseHandle( Token );
  674. }
  675. if (GetProfileStringA( szDebugSection,
  676. szDebugFlags,
  677. "",
  678. Line,
  679. MAX_PATH))
  680. {
  681. pHeader->fDebug |= DbgpGetBitmask( DbgpKeys,
  682. DEBUG_NUMBER_OF_KEYS,
  683. Line,
  684. 3,
  685. LogFile);
  686. }
  687. if ( pHeader->fDebug & DEBUG_USE_KDEBUG )
  688. {
  689. //
  690. // Verify that there is a kernel debugger
  691. //
  692. SYSTEM_KERNEL_DEBUGGER_INFORMATION KdInfo ;
  693. NTSTATUS Status ;
  694. Status = NtQuerySystemInformation(
  695. SystemKernelDebuggerInformation,
  696. &KdInfo,
  697. sizeof( KdInfo ),
  698. NULL );
  699. if ( NT_SUCCESS( Status ) )
  700. {
  701. if ( !KdInfo.KernelDebuggerEnabled )
  702. {
  703. pHeader->fDebug &= ~(DEBUG_USE_KDEBUG) ;
  704. }
  705. }
  706. }
  707. if (pHeader->fDebug & DEBUG_LOGFILE)
  708. {
  709. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  710. sa.lpSecurityDescriptor = &DbgpPartySd;
  711. sa.bInheritHandle = FALSE;
  712. if (LogFile[0] == '\0')
  713. {
  714. strcpy(LogFile, szExeName);
  715. strcat(LogFile, ".log");
  716. }
  717. pHeader->hLogFile = CreateFileA(LogFile,
  718. GENERIC_READ | GENERIC_WRITE,
  719. FILE_SHARE_READ,
  720. &sa,
  721. CREATE_ALWAYS,
  722. FILE_ATTRIBUTE_NORMAL |
  723. FILE_FLAG_WRITE_THROUGH,
  724. NULL);
  725. }
  726. pHeader->pModules = pModule;
  727. pHeader->pGlobalModule = pModule;
  728. pModule->pInfoLevel = &pHeader->fDebug;
  729. pModule->InfoLevel = pHeader->fDebug;
  730. DbgpAttachBuiltinModules(pHeader);
  731. }
  732. //+---------------------------------------------------------------------------
  733. //
  734. // Function: DbgpOpenLogFileRandom
  735. //
  736. // Synopsis: Opens the logfile dynamically
  737. //
  738. // Arguments: [pHeader] --
  739. //
  740. // History: 4-27-95 RichardW Created
  741. //
  742. // Notes:
  743. //
  744. //----------------------------------------------------------------------------
  745. BOOL
  746. DbgpOpenLogFileRandom(
  747. PDebugHeader pHeader)
  748. {
  749. WCHAR szLogPath[MAX_PATH];
  750. DWORD dwPath;
  751. PWSTR pszDot;
  752. SECURITY_ATTRIBUTES sa;
  753. dwPath = GetModuleFileName(NULL, szLogPath, MAX_PATH);
  754. pszDot = wcsrchr(szLogPath, L'.');
  755. if (!pszDot)
  756. {
  757. pszDot = &szLogPath[dwPath];
  758. }
  759. wcscpy(pszDot, L".log");
  760. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  761. sa.lpSecurityDescriptor = &DbgpPartySd;
  762. sa.bInheritHandle = FALSE;
  763. LockDebugHeader(pHeader);
  764. pHeader->hLogFile = CreateFileW(szLogPath,
  765. GENERIC_READ | GENERIC_WRITE,
  766. FILE_SHARE_READ,
  767. &sa,
  768. CREATE_ALWAYS,
  769. FILE_ATTRIBUTE_NORMAL |
  770. FILE_FLAG_WRITE_THROUGH,
  771. NULL);
  772. if (pHeader->hLogFile == INVALID_HANDLE_VALUE)
  773. {
  774. pHeader->fDebug &= ~(DEBUG_LOGFILE);
  775. UnlockDebugHeader(pHeader);
  776. return(FALSE);
  777. }
  778. UnlockDebugHeader(pHeader);
  779. return(TRUE);
  780. }
  781. //+---------------------------------------------------------------------------
  782. //
  783. // Function: DbgpOpenOrCreateSharedMem
  784. //
  785. // Synopsis: Returns a pointer to the shared memory segment,
  786. // creating it if necessary. Header is LOCKED on return
  787. //
  788. // Arguments: (none)
  789. //
  790. // History: 3-22-95 RichardW Created
  791. //
  792. // Notes:
  793. //
  794. //----------------------------------------------------------------------------
  795. PVOID
  796. DbgpOpenOrCreateSharedMem(DWORD Flags)
  797. {
  798. HANDLE hMapping;
  799. WCHAR szMappingName[32];
  800. SECURITY_ATTRIBUTES sa;
  801. PDebugHeader pHeader;
  802. SYSTEM_INFO SysInfo;
  803. if (!DbgpPartySdInit)
  804. {
  805. InitializeSecurityDescriptor(&DbgpPartySd, SECURITY_DESCRIPTOR_REVISION);
  806. SetSecurityDescriptorDacl(&DbgpPartySd, TRUE, NULL, FALSE);
  807. DbgpPartySdInit = TRUE;
  808. }
  809. if (DbgpHeader)
  810. {
  811. LockDebugHeader(DbgpHeader);
  812. return(DbgpHeader);
  813. }
  814. GetSystemInfo(&SysInfo);
  815. DbgpComputeMappingName(szMappingName);
  816. hMapping = OpenFileMapping( FILE_MAP_ALL_ACCESS,
  817. FALSE,
  818. szMappingName);
  819. if (hMapping)
  820. {
  821. //
  822. // Ok, someone else has created the section. So, we just need to map
  823. // it.
  824. //
  825. pHeader = MapViewOfFileEx( hMapping,
  826. FILE_MAP_READ | FILE_MAP_WRITE,
  827. 0,
  828. 0,
  829. SysInfo.dwPageSize,
  830. NULL);
  831. if ( pHeader )
  832. {
  833. if (pHeader != pHeader->pvSection)
  834. {
  835. DbgpHeader = pHeader->pvSection;
  836. }
  837. else
  838. {
  839. DbgpHeader = pHeader;
  840. }
  841. UnmapViewOfFile(pHeader);
  842. }
  843. else
  844. {
  845. DbgpHeader = NULL ;
  846. }
  847. //
  848. // Now that we have the other guy's address, we can throw away this
  849. // one.
  850. //
  851. CloseHandle(hMapping);
  852. if ( DbgpHeader )
  853. {
  854. LockDebugHeader(DbgpHeader);
  855. DbgpAttachBuiltinModules(DbgpHeader);
  856. }
  857. return(DbgpHeader);
  858. }
  859. if (Flags & DSYSDBG_OPEN_ONLY)
  860. {
  861. return(NULL);
  862. }
  863. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  864. sa.lpSecurityDescriptor = &DbgpPartySd;
  865. sa.bInheritHandle = FALSE;
  866. hMapping = CreateFileMapping( INVALID_HANDLE_VALUE,
  867. NULL, //&sa,
  868. PAGE_READWRITE | SEC_RESERVE,
  869. 0,
  870. SysInfo.dwAllocationGranularity,
  871. szMappingName);
  872. if (hMapping)
  873. {
  874. pHeader = MapViewOfFileEx(hMapping,
  875. FILE_MAP_READ | FILE_MAP_WRITE,
  876. 0,
  877. 0,
  878. SysInfo.dwAllocationGranularity,
  879. NULL);
  880. if (!pHeader)
  881. {
  882. return(NULL);
  883. }
  884. //
  885. // Commit the view, so we can initialize the header
  886. //
  887. pHeader = (PDebugHeader) VirtualAlloc( pHeader,
  888. SysInfo.dwPageSize,
  889. MEM_COMMIT,
  890. PAGE_READWRITE);
  891. pHeader->Tag = DEBUG_TAG;
  892. pHeader->pvSection = pHeader;
  893. pHeader->hMapping = hMapping;
  894. pHeader->hLogFile = INVALID_HANDLE_VALUE;
  895. pHeader->CommitRange = SysInfo.dwPageSize;
  896. pHeader->ReserveRange = SysInfo.dwAllocationGranularity;
  897. pHeader->PageSize = SysInfo.dwPageSize;
  898. pHeader->pModules = NULL;
  899. pHeader->pFreeList = NULL;
  900. pHeader->pBufferList = &pHeader->DefaultBuffer ;
  901. pHeader->DefaultBuffer.Next = NULL ;
  902. InitializeCriticalSection(&pHeader->csDebug);
  903. LockDebugHeader(pHeader);
  904. DbgpInitializeMM(pHeader);
  905. DbgpInitializeDebug(pHeader);
  906. DbgpHeader = pHeader;
  907. return(pHeader);
  908. }
  909. return(NULL);
  910. }
  911. //+---------------------------------------------------------------------------
  912. //
  913. // Function: DbgpLoadValidateRoutine
  914. //
  915. // Synopsis: Loads RtlValidateProcessHeaps() from ntdll
  916. //
  917. // Arguments: [pHeader] --
  918. //
  919. // History: 5-02-95 RichardW Created
  920. //
  921. // Notes:
  922. //
  923. //----------------------------------------------------------------------------
  924. VOID
  925. DbgpLoadValidateRoutine(PDebugHeader pHeader)
  926. {
  927. HMODULE hNtDll;
  928. hNtDll = LoadLibrary(TEXT("ntdll.dll"));
  929. if (hNtDll)
  930. {
  931. pHeader->pfnValidate = (HEAPVALIDATE) GetProcAddress(hNtDll, "RtlValidateProcessHeaps");
  932. if (!pHeader->pfnValidate)
  933. {
  934. pHeader->fDebug &= ~(DEBUG_HEAP_CHECK);
  935. }
  936. //
  937. // We can safely free this handle, since kernel32 and advapi32 DLLs
  938. // both use ntdll, so the refcount won't go to zero.
  939. //
  940. FreeLibrary(hNtDll);
  941. }
  942. }
  943. //+---------------------------------------------------------------------------
  944. //
  945. // Function: _InitDebug
  946. //
  947. // Synopsis: Workhorse of the initializers
  948. //
  949. // Arguments: [pInfoLevel] -- Pointer to module specific infolevel
  950. // [ppControlBlock] -- Pointer to module specific control pointer
  951. // [szName] -- Name
  952. // [pKeys] -- Key data
  953. //
  954. // History: 3-22-95 RichardW Created
  955. //
  956. // Notes:
  957. //
  958. //----------------------------------------------------------------------------
  959. VOID
  960. _InitDebug(
  961. DWORD Flags,
  962. DWORD * pInfoLevel,
  963. PVOID * ppControlBlock,
  964. CHAR * szName,
  965. PDEBUG_KEY pKeys)
  966. {
  967. PDebugHeader pHeader;
  968. PDebugModule pModule;
  969. CHAR Line[MAX_PATH];
  970. DWORD cKeys;
  971. DWORD i;
  972. if ( (*ppControlBlock) && (*ppControlBlock != INVALID_HANDLE_VALUE) )
  973. {
  974. //
  975. // Already Initialized
  976. //
  977. return ;
  978. }
  979. *ppControlBlock = NULL;
  980. //
  981. // Find the shared section.
  982. //
  983. pHeader = DbgpOpenOrCreateSharedMem(Flags);
  984. if (!pHeader)
  985. {
  986. if (Flags & DSYSDBG_DEMAND_OPEN)
  987. {
  988. *ppControlBlock = (PVOID) INVALID_HANDLE_VALUE;
  989. }
  990. return;
  991. }
  992. //
  993. // See if we have already registered (dll being loaded several times)
  994. // if not, allocate a new module.
  995. //
  996. pModule = DbgpFindModule(pHeader, szName);
  997. if (!pModule)
  998. {
  999. pModule = DbgpAlloc(pHeader, sizeof(DebugModule) );
  1000. if (!pModule)
  1001. {
  1002. UnlockDebugHeader(pHeader);
  1003. return;
  1004. }
  1005. }
  1006. else
  1007. {
  1008. //
  1009. // Found module already loaded. Check to see that everything
  1010. // lines up:
  1011. //
  1012. if ( pModule->pInfoLevel != pInfoLevel )
  1013. {
  1014. //
  1015. // Uh oh, there's a module with our name already loaded,
  1016. // but the pointers don't match. So, let's create our
  1017. // own now.
  1018. //
  1019. pModule = DbgpAlloc( pHeader, sizeof( DebugModule ) );
  1020. if ( !pModule )
  1021. {
  1022. UnlockDebugHeader( pHeader );
  1023. return;
  1024. }
  1025. }
  1026. else
  1027. {
  1028. *ppControlBlock = pModule;
  1029. UnlockDebugHeader(pHeader);
  1030. return;
  1031. }
  1032. }
  1033. //
  1034. // Initialize module
  1035. //
  1036. cKeys = DbgpBuildModule(pModule,
  1037. pHeader,
  1038. pKeys,
  1039. szName,
  1040. pInfoLevel);
  1041. //
  1042. // Now, load up info levels from ini or registry
  1043. // First, try a module specific entry.
  1044. //
  1045. if (GetProfileStringA(szName, szDebugFlags, "", Line, MAX_PATH))
  1046. {
  1047. pModule->InfoLevel = DbgpGetBitmask(pKeys,
  1048. cKeys,
  1049. Line,
  1050. 0xFFFFFFFF,
  1051. NULL );
  1052. }
  1053. if (pHeader->pszExeName)
  1054. {
  1055. if (GetProfileStringA(szName, pHeader->pszExeName, "", Line, MAX_PATH))
  1056. {
  1057. pModule->InfoLevel = DbgpGetBitmask(pKeys,
  1058. cKeys,
  1059. Line,
  1060. 0xFFFFFFFF,
  1061. NULL );
  1062. }
  1063. }
  1064. // HACK - Make Default DBG / DEBUG_SUPPORT dependent. See dsysdbg.h
  1065. if (GetProfileStringA(szDebugSection, szName, SZ_DEFAULT_PROFILE_STRING, Line, MAX_PATH))
  1066. {
  1067. pModule->InfoLevel |= DbgpGetBitmask( pKeys,
  1068. cKeys,
  1069. Line,
  1070. 0xFFFFFFFF,
  1071. NULL );
  1072. }
  1073. *pModule->pInfoLevel = pModule->InfoLevel;
  1074. pModule->pNext = pHeader->pModules;
  1075. pHeader->pModules = pModule;
  1076. pHeader->ModuleCount++ ;
  1077. *ppControlBlock = pModule;
  1078. UnlockDebugHeader(pHeader);
  1079. }
  1080. VOID
  1081. _UnloadDebug(
  1082. PVOID pControlBlock
  1083. )
  1084. {
  1085. PDebugHeader pHeader;
  1086. PDebugModule pModule;
  1087. PDebugModule pScan ;
  1088. BOOL FreeIt = FALSE ;
  1089. pModule = (PDebugModule) pControlBlock ;
  1090. if ( !pModule )
  1091. {
  1092. return ;
  1093. }
  1094. if ( pModule->pInfoLevel == NULL )
  1095. {
  1096. return ;
  1097. }
  1098. pHeader = pModule->pHeader ;
  1099. LockDebugHeader( pHeader );
  1100. pScan = pHeader->pModules ;
  1101. if ( pScan == pModule )
  1102. {
  1103. pHeader->pModules = pModule->pNext ;
  1104. }
  1105. else
  1106. {
  1107. while ( pScan && ( pScan->pNext != pModule ) )
  1108. {
  1109. pScan = pScan->pNext ;
  1110. }
  1111. if ( pScan )
  1112. {
  1113. pScan->pNext = pModule->pNext ;
  1114. }
  1115. pModule->pNext = NULL ;
  1116. }
  1117. DbgpFree( pHeader, pModule->pModuleName );
  1118. DbgpFree( pHeader, pModule );
  1119. pHeader->ModuleCount-- ;
  1120. if ( pHeader->ModuleCount == 0 )
  1121. {
  1122. FreeIt = TRUE ;
  1123. }
  1124. UnlockDebugHeader( pHeader );
  1125. if ( FreeIt )
  1126. {
  1127. if ( pHeader->hLogFile != INVALID_HANDLE_VALUE )
  1128. {
  1129. CloseHandle( pHeader->hLogFile );
  1130. }
  1131. if ( pHeader->hMapping )
  1132. {
  1133. CloseHandle( pHeader->hMapping );
  1134. }
  1135. DeleteCriticalSection( &pHeader->csDebug );
  1136. UnmapViewOfFile( pHeader );
  1137. }
  1138. }
  1139. //+---------------------------------------------------------------------------
  1140. //
  1141. // Function: DbgpGetTextBuffer
  1142. //
  1143. // Synopsis: Gets a text buffer from the header, allocating if necessary
  1144. //
  1145. // Arguments: [pHeader] --
  1146. //
  1147. // History: 3-19-98 RichardW Created
  1148. //
  1149. // Notes:
  1150. //
  1151. //----------------------------------------------------------------------------
  1152. PDEBUG_TEXT_BUFFER
  1153. DbgpGetTextBuffer(
  1154. PDebugHeader pHeader
  1155. )
  1156. {
  1157. PDEBUG_TEXT_BUFFER pBuffer ;
  1158. LockDebugHeader( pHeader );
  1159. if ( pHeader->pBufferList )
  1160. {
  1161. pBuffer = pHeader->pBufferList ;
  1162. pHeader->pBufferList = pBuffer->Next ;
  1163. }
  1164. else
  1165. {
  1166. pBuffer = DbgpAlloc( pHeader, sizeof( DEBUG_TEXT_BUFFER ) );
  1167. }
  1168. UnlockDebugHeader( pHeader );
  1169. if ( pBuffer )
  1170. {
  1171. pBuffer->Next = NULL ;
  1172. }
  1173. return pBuffer ;
  1174. }
  1175. //+---------------------------------------------------------------------------
  1176. //
  1177. // Function: DbgpReleaseTextBuffer
  1178. //
  1179. // Synopsis: Releases a text buffer back to the pool of buffers
  1180. //
  1181. // Arguments: [pHeader] --
  1182. // [pBuffer] --
  1183. //
  1184. // History: 3-19-98 RichardW Created
  1185. //
  1186. // Notes:
  1187. //
  1188. //----------------------------------------------------------------------------
  1189. VOID
  1190. DbgpReleaseTextBuffer(
  1191. PDebugHeader pHeader,
  1192. PDEBUG_TEXT_BUFFER pBuffer
  1193. )
  1194. {
  1195. LockDebugHeader( pHeader );
  1196. pBuffer->Next = pHeader->pBufferList ;
  1197. pHeader->pBufferList = pBuffer ;
  1198. UnlockDebugHeader( pHeader );
  1199. }
  1200. //+---------------------------------------------------------------------------
  1201. //
  1202. // Function: _DebugOut
  1203. //
  1204. // Synopsis: Workhorse for the debug out functions
  1205. //
  1206. // Arguments: [pControl] -- Control pointer
  1207. // [Mask] -- Event mask
  1208. // [Format] -- format string
  1209. // [ArgList] -- va_list...
  1210. //
  1211. // History: 3-22-95 RichardW Created
  1212. //
  1213. // Notes:
  1214. //
  1215. //----------------------------------------------------------------------------
  1216. VOID
  1217. _DebugOut(
  1218. PVOID pControl,
  1219. ULONG Mask,
  1220. CHAR * Format,
  1221. va_list ArgList)
  1222. {
  1223. PDebugModule pModule;
  1224. int Level = 0;
  1225. int PrefixSize = 0;
  1226. int TotalSize;
  1227. BOOL fLocked;
  1228. BOOL fClean;
  1229. PCHAR Tag;
  1230. BOOL Break = FALSE ;
  1231. PDEBUG_TEXT_BUFFER pBuffer ;
  1232. if ( pControl == NULL )
  1233. {
  1234. return ;
  1235. }
  1236. pModule = (PDebugModule) pControl;
  1237. if ( pModule->pInfoLevel == NULL )
  1238. {
  1239. return ;
  1240. }
  1241. if (!pModule || (pModule == INVALID_HANDLE_VALUE))
  1242. {
  1243. if (Mask & DSYSDBG_FORCE)
  1244. {
  1245. NOTHING ;
  1246. }
  1247. else
  1248. return;
  1249. }
  1250. if (pModule->fModule & DEBUGMOD_CHANGE_INFOLEVEL)
  1251. {
  1252. *pModule->pInfoLevel = pModule->InfoLevel;
  1253. pModule->fModule &= ~(DEBUGMOD_CHANGE_INFOLEVEL);
  1254. }
  1255. if (pModule->pHeader->pGlobalModule->fModule & DEBUGMOD_CHANGE_INFOLEVEL)
  1256. {
  1257. pModule->pHeader->fDebug = pModule->pHeader->pGlobalModule->InfoLevel;
  1258. pModule->pHeader->pGlobalModule->fModule &= ~(DEBUGMOD_CHANGE_INFOLEVEL);
  1259. }
  1260. pModule->InfoLevel = *pModule->pInfoLevel;
  1261. if (pModule->pHeader->fDebug & DEBUG_MULTI_THREAD)
  1262. {
  1263. LockDebugHeader(pModule->pHeader);
  1264. fLocked = TRUE;
  1265. }
  1266. else
  1267. fLocked = FALSE;
  1268. if (pModule->pHeader->fDebug & DEBUG_HEAP_CHECK)
  1269. {
  1270. if (!pModule->pHeader->pfnValidate)
  1271. {
  1272. DbgpLoadValidateRoutine(pModule->pHeader);
  1273. }
  1274. if (pModule->pHeader->pfnValidate)
  1275. {
  1276. pModule->pHeader->pfnValidate();
  1277. }
  1278. }
  1279. fClean = ((Mask & DSYSDBG_CLEAN) != 0);
  1280. if ( ( Mask & DEB_ERROR ) &&
  1281. ( pModule->pHeader->fDebug & DEBUG_BREAK_ON_ERROR ) )
  1282. {
  1283. Break = TRUE ;
  1284. }
  1285. pBuffer = DbgpGetTextBuffer( pModule->pHeader );
  1286. if ( !pBuffer )
  1287. {
  1288. OutputDebugStringA( "_DebugOut : Out of memory\n" );
  1289. if ( fLocked )
  1290. {
  1291. UnlockDebugHeader( pModule->pHeader );
  1292. }
  1293. return;
  1294. }
  1295. if (Mask & (pModule->InfoLevel | DSYSDBG_FORCE))
  1296. {
  1297. if (Mask & DSYSDBG_FORCE)
  1298. {
  1299. Tag = "FORCE";
  1300. }
  1301. else
  1302. {
  1303. while (!(Mask & 1))
  1304. {
  1305. Level++;
  1306. Mask >>= 1;
  1307. }
  1308. Tag = pModule->TagLevels[Level];
  1309. }
  1310. //
  1311. // Make the prefix first: "Process.Thread> Module-Tag:
  1312. //
  1313. if (!fClean)
  1314. {
  1315. if (pModule->pHeader->fDebug & DEBUG_TIMESTAMP)
  1316. {
  1317. SYSTEMTIME stTime;
  1318. GetLocalTime(&stTime);
  1319. PrefixSize = sprintf(pBuffer->TextBuffer,
  1320. "[%2d/%2d %02d:%02d:%02d] %d.%d> %s-%s: ",
  1321. stTime.wMonth, stTime.wDay,
  1322. stTime.wHour, stTime.wMinute, stTime.wSecond,
  1323. GetCurrentProcessId(),
  1324. GetCurrentThreadId(), pModule->pModuleName,
  1325. Tag);
  1326. }
  1327. else
  1328. {
  1329. PrefixSize = sprintf(pBuffer->TextBuffer, "%d.%d> %s-%s: ",
  1330. GetCurrentProcessId(), GetCurrentThreadId(),
  1331. pModule->pModuleName, Tag);
  1332. }
  1333. }
  1334. if ((TotalSize = _vsnprintf(&pBuffer->TextBuffer[PrefixSize],
  1335. DEBUG_TEXT_BUFFER_SIZE - PrefixSize,
  1336. Format, ArgList)) < 0)
  1337. {
  1338. //
  1339. // Less than zero indicates that the string could not be
  1340. // fitted into the buffer. Output a special message indicating
  1341. // that:
  1342. //
  1343. OutputDebugStringA("dsysdbg: Could not pack string into 512 bytes\n");
  1344. }
  1345. else
  1346. {
  1347. TotalSize += PrefixSize;
  1348. if ((pModule->pHeader->fDebug & DEBUG_NO_DEBUGIO) == 0 )
  1349. {
  1350. OutputDebugStringA( pBuffer->TextBuffer );
  1351. }
  1352. if ((pModule->pHeader->fDebug & DEBUG_LOGFILE))
  1353. {
  1354. if (pModule->pHeader->hLogFile == INVALID_HANDLE_VALUE)
  1355. {
  1356. DbgpOpenLogFileRandom(pModule->pHeader);
  1357. }
  1358. WriteFile( pModule->pHeader->hLogFile,
  1359. pBuffer->TextBuffer,
  1360. (DWORD) TotalSize,
  1361. (PDWORD) &PrefixSize,
  1362. NULL );
  1363. }
  1364. pModule->pHeader->TotalWritten += TotalSize;
  1365. pModule->TotalOutput += TotalSize;
  1366. }
  1367. }
  1368. if (fLocked)
  1369. {
  1370. UnlockDebugHeader(pModule->pHeader);
  1371. }
  1372. DbgpReleaseTextBuffer( pModule->pHeader, pBuffer );
  1373. if ( Break )
  1374. {
  1375. OutputDebugStringA( "BreakOnError\n" );
  1376. DebugBreak();
  1377. }
  1378. }
  1379. VOID
  1380. _DbgSetOption(
  1381. PVOID pControl,
  1382. DWORD Option,
  1383. BOOL On,
  1384. BOOL Global
  1385. )
  1386. {
  1387. PDebugModule pModule;
  1388. pModule = (PDebugModule) pControl ;
  1389. if ( pModule )
  1390. {
  1391. if ( Global )
  1392. {
  1393. pModule = pModule->pHeader->pGlobalModule ;
  1394. }
  1395. if ( On )
  1396. {
  1397. pModule->InfoLevel |= Option ;
  1398. *pModule->pInfoLevel |= Option ;
  1399. }
  1400. else
  1401. {
  1402. pModule->InfoLevel &= (~Option) ;
  1403. *pModule->pInfoLevel &= (~Option) ;
  1404. }
  1405. }
  1406. }
  1407. VOID
  1408. _DbgSetLoggingOption(
  1409. PVOID pControl,
  1410. BOOL On
  1411. )
  1412. {
  1413. PDebugModule pModule;
  1414. pModule = (PDebugModule)pControl;
  1415. if ( pModule )
  1416. {
  1417. if (((pModule->pHeader->fDebug & DEBUG_LOGFILE) == 0) && On )// off, turn it on
  1418. {
  1419. pModule->pHeader->fDebug |= DEBUG_LOGFILE;
  1420. }
  1421. else if ((pModule->pHeader->fDebug & DEBUG_LOGFILE) && !On) // on, turn it off
  1422. {
  1423. pModule->pHeader->fDebug &= (~DEBUG_LOGFILE);
  1424. if ( pModule->pHeader->hLogFile != INVALID_HANDLE_VALUE )
  1425. {
  1426. CloseHandle( pModule->pHeader->hLogFile );
  1427. pModule->pHeader->hLogFile = INVALID_HANDLE_VALUE;
  1428. }
  1429. }
  1430. }
  1431. }