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.

602 lines
15 KiB

  1. //+--------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992
  5. //
  6. // File: debug.cxx
  7. //
  8. // Contents: Debugging routines
  9. //
  10. // History: 07-Mar-92 DrewB Created
  11. //
  12. //---------------------------------------------------------------
  13. #include <dfhead.cxx>
  14. #pragma hdrstop
  15. #if DBG == 1
  16. //#include <w4wchar.h>
  17. #include <stdarg.h>
  18. #include <dfdeb.hxx>
  19. #include <logfile.hxx>
  20. #include <df32.hxx>
  21. //+-------------------------------------------------------------
  22. //
  23. // Function: DfDebug, public
  24. //
  25. // Synopsis: Sets debugging level
  26. //
  27. //---------------------------------------------------------------
  28. DECLARE_INFOLEVEL(ol);
  29. #define LOGFILENAME L"logfile.txt"
  30. static CGlobalFileStream *_pgfstLogFiles = NULL;
  31. WCHAR gwcsLogFile[] = LOGFILENAME;
  32. STDAPI_(void) DfDebug(ULONG ulLevel, ULONG ulMSFLevel)
  33. {
  34. #if DBG == 1
  35. olInfoLevel = ulLevel;
  36. SetInfoLevel(ulMSFLevel);
  37. _SetWin4InfoLevel(ulLevel | ulMSFLevel);
  38. olDebugOut((DEB_ITRACE, "\n-- DfDebug(0x%lX, 0x%lX)\n",
  39. ulLevel, ulMSFLevel));
  40. #endif
  41. }
  42. // Resource limits
  43. static LONG lResourceLimits[CDBRESOURCES] =
  44. {
  45. 0x7fffffff, // DBR_MEMORY
  46. 0x7fffffff, // DBR_XSCOMMITS
  47. 0x0, // DBR_FAILCOUNT
  48. 0x0, // DBR_FAILLIMIT
  49. 0x0, // DBR_FAILTYPES
  50. 0x0, // DBRQ_MEMORY_ALLOCATED
  51. 0x0, // DBRI_ALLOC_LIST
  52. 0x0, // DBRI_LOGFILE_LIST
  53. 0x0, // DBRF_LOGGING
  54. 0x0, // DBRQ_HEAPS
  55. 0x0 // DBRF_SIFTENABLE
  56. };
  57. #define CBRESOURCES sizeof(lResourceLimits)
  58. #define RESLIMIT(n) lResourceLimits[n]
  59. #define TAKEMTX
  60. #define RELEASEMTX
  61. //+---------------------------------------------------------------------------
  62. //
  63. // Function: DfSetResLimit, public
  64. //
  65. // Synopsis: Sets a resource limit
  66. //
  67. // History: 24-Nov-92 DrewB Created
  68. //
  69. //----------------------------------------------------------------------------
  70. STDAPI_(void) DfSetResLimit(UINT iRes, LONG lLimit)
  71. {
  72. TAKEMTX;
  73. RESLIMIT(iRes) = lLimit;
  74. RELEASEMTX;
  75. }
  76. //+---------------------------------------------------------------------------
  77. //
  78. // Function: DfGetResLimit, public
  79. //
  80. // Synopsis: Gets a resource limit
  81. //
  82. // History: 24-Nov-92 DrewB Created
  83. //
  84. //----------------------------------------------------------------------------
  85. STDAPI_(LONG) DfGetResLimit(UINT iRes)
  86. {
  87. // Doesn't need serialization
  88. return RESLIMIT(iRes);
  89. }
  90. STDAPI_(void) DfSetFailureType(LONG lTypes)
  91. {
  92. RESLIMIT(DBR_FAILTYPES) = lTypes;
  93. return;
  94. }
  95. //+---------------------------------------------------------------------------
  96. //
  97. // Function: HaveResource, private
  98. //
  99. // Synopsis: Checks to see if a resource limit is exceeded
  100. // and consumes resource if not
  101. //
  102. // History: 24-Nov-92 DrewB Created
  103. //
  104. //----------------------------------------------------------------------------
  105. BOOL HaveResource(UINT iRes, LONG lRequest)
  106. {
  107. if (RESLIMIT(DBRF_SIFTENABLE) == FALSE)
  108. return TRUE;
  109. if (RESLIMIT(iRes) >= lRequest)
  110. {
  111. TAKEMTX;
  112. RESLIMIT(iRes) -= lRequest;
  113. RELEASEMTX;
  114. return TRUE;
  115. }
  116. return FALSE;
  117. }
  118. //+---------------------------------------------------------------------------
  119. //
  120. // Function: ModifyResLimit, private
  121. //
  122. // Synopsis: Adds to a resource limit
  123. //
  124. // History: 24-Nov-92 DrewB Created
  125. //
  126. //----------------------------------------------------------------------------
  127. LONG ModifyResLimit(UINT iRes, LONG lChange)
  128. {
  129. LONG l;
  130. TAKEMTX;
  131. RESLIMIT(iRes) += lChange;
  132. l = RESLIMIT(iRes);
  133. RELEASEMTX;
  134. return l;
  135. }
  136. //+-------------------------------------------------------------------------
  137. //
  138. // Function: SimulateFailure
  139. //
  140. // Synopsis: Check for simulated failure
  141. //
  142. // Effects: Tracks failure count
  143. //
  144. // Arguments: [failure] -- failure type
  145. //
  146. // Returns: TRUE if call should fail, FALSE if call should succeed
  147. //
  148. // Modifies: RESLIMIT(DBR_FAILCOUNT)
  149. //
  150. // Algorithm: Increment failure count, fail if count has succeeded
  151. // limit
  152. //
  153. // History: 21-Jan-93 AlexT Created
  154. //
  155. //--------------------------------------------------------------------------
  156. BOOL SimulateFailure(DBFAILURE failure)
  157. {
  158. LONG l;
  159. BOOL fFail;
  160. // We don't special case failure types, yet.
  161. if (RESLIMIT(DBRF_SIFTENABLE) != FALSE &&
  162. (failure & RESLIMIT(DBR_FAILTYPES)))
  163. {
  164. TAKEMTX;
  165. RESLIMIT(DBR_FAILCOUNT)++;
  166. l = RESLIMIT(DBR_FAILLIMIT);
  167. fFail = RESLIMIT(DBR_FAILCOUNT) >= l;
  168. RELEASEMTX;
  169. if (l == 0)
  170. {
  171. // We're not simulating any failures; just tracking them
  172. return(FALSE);
  173. }
  174. return fFail;
  175. }
  176. else
  177. {
  178. return FALSE;
  179. }
  180. }
  181. //+--------------------------------------------------------------
  182. //
  183. // Class: CChecksumBlock (cb)
  184. //
  185. // Purpose: Holds a memory block that is being checksummed
  186. //
  187. // Interface: See below
  188. //
  189. // History: 08-Apr-92 DrewB Created
  190. //
  191. //---------------------------------------------------------------
  192. class CChecksumBlock
  193. {
  194. public:
  195. CChecksumBlock(char *pszName,
  196. void *pvAddr,
  197. ULONG cBytes,
  198. DWORD dwFlags,
  199. CChecksumBlock *pcbNext,
  200. CChecksumBlock *pcbPrev);
  201. ~CChecksumBlock(void);
  202. char *_pszName;
  203. void *_pvAddr;
  204. ULONG _cBytes;
  205. DWORD _dwFlags;
  206. CChecksumBlock *_pcbNext, *_pcbPrev;
  207. ULONG _ulChecksum;
  208. };
  209. // Global list of checksummed blocks
  210. static CChecksumBlock *pcbChkBlocks = NULL;
  211. //+--------------------------------------------------------------
  212. //
  213. // Member: CChecksumBlock::CChecksumBlock, private
  214. //
  215. // Synopsis: Ctor
  216. //
  217. // Arguments: [pszName] - Block name
  218. // [pvAddr] - Starting addr
  219. // [cBytes] - Length
  220. // [dwFlags] - Type flags
  221. // [pcbNext] - Next checksum block
  222. //
  223. // History: 08-Apr-92 DrewB Created
  224. //
  225. //---------------------------------------------------------------
  226. CChecksumBlock::CChecksumBlock(char *pszName,
  227. void *pvAddr,
  228. ULONG cBytes,
  229. DWORD dwFlags,
  230. CChecksumBlock *pcbNext,
  231. CChecksumBlock *pcbPrev)
  232. {
  233. ULONG i;
  234. char *pc;
  235. olVerify(_pszName = new char[strlen(pszName)+1]);
  236. strcpy(_pszName, pszName);
  237. _pvAddr = pvAddr;
  238. _cBytes = cBytes;
  239. _dwFlags = dwFlags;
  240. _pcbNext = pcbNext;
  241. if (pcbNext)
  242. pcbNext->_pcbPrev = this;
  243. _pcbPrev = pcbPrev;
  244. if (pcbPrev)
  245. pcbPrev->_pcbNext = this;
  246. _ulChecksum = 0;
  247. pc = (char *)pvAddr;
  248. for (i = 0; i<cBytes; i++)
  249. _ulChecksum += *pc++;
  250. }
  251. //+--------------------------------------------------------------
  252. //
  253. // Member: CChecksumBlock::~CChecksumBlock, private
  254. //
  255. // Synopsis: Dtor
  256. //
  257. // History: 08-Apr-92 DrewB Created
  258. //
  259. //---------------------------------------------------------------
  260. CChecksumBlock::~CChecksumBlock(void)
  261. {
  262. delete _pszName;
  263. }
  264. //+--------------------------------------------------------------
  265. //
  266. // Function: DbgChkBlocks, private
  267. //
  268. // Synopsis: Verify checksums on all current blocks
  269. //
  270. // Arguments: [dwFlags] - Types of blocks to check
  271. // [pszFile] - File check was called from
  272. // [iLine] - Line in file
  273. //
  274. // History: 08-Apr-92 DrewB Created
  275. //
  276. //---------------------------------------------------------------
  277. void DbgChkBlocks(DWORD dwFlags, char *pszFile, int iLine)
  278. {
  279. CChecksumBlock *pcb;
  280. for (pcb = pcbChkBlocks; pcb; pcb = pcb->_pcbNext)
  281. if (pcb->_dwFlags & dwFlags)
  282. {
  283. ULONG i, ulSum = 0;
  284. char *pc;
  285. for (pc = (char *)pcb->_pvAddr, i = 0; i<pcb->_cBytes; i++)
  286. ulSum += *pc++;
  287. if (ulSum != pcb->_ulChecksum)
  288. olDebugOut((DEB_ERROR, "* Bad checksum %s:%d '%s' %p:%lu *\n",
  289. pszFile, iLine, pcb->_pszName,
  290. pcb->_pvAddr, pcb->_cBytes));
  291. else if (dwFlags & DBG_VERBOSE)
  292. olDebugOut((DEB_ERROR, "* Checksum passed %s:%d"
  293. " '%s' %p:%lu *\n",
  294. pszFile, iLine, pcb->_pszName,
  295. pcb->_pvAddr, pcb->_cBytes));
  296. }
  297. }
  298. //+--------------------------------------------------------------
  299. //
  300. // Function: DbgAddChkBlock, private
  301. //
  302. // Synopsis: Adds a checksum block
  303. //
  304. // Arguments: [pszName] - Name of block
  305. // [pvAddr] - Starting addr
  306. // [cBytes] - Length
  307. // [dwFlags] - Type flags
  308. //
  309. // History: 08-Apr-92 DrewB Created
  310. //
  311. //---------------------------------------------------------------
  312. void DbgAddChkBlock(char *pszName,
  313. void *pvAddr,
  314. ULONG cBytes,
  315. DWORD dwFlags)
  316. {
  317. CChecksumBlock *pcb;
  318. olVerify(pcb = new CChecksumBlock(pszName, pvAddr, cBytes,
  319. dwFlags, pcbChkBlocks, NULL));
  320. pcbChkBlocks = pcb;
  321. }
  322. //+--------------------------------------------------------------
  323. //
  324. // Function: DbgFreeChkBlock, private
  325. //
  326. // Synopsis: Removes a block from the list
  327. //
  328. // Arguments: [pvAddr] - Block's check address
  329. //
  330. // History: 10-Apr-92 DrewB Created
  331. //
  332. //---------------------------------------------------------------
  333. void DbgFreeChkBlock(void *pvAddr)
  334. {
  335. CChecksumBlock *pcb;
  336. for (pcb = pcbChkBlocks; pcb; pcb = pcb->_pcbNext)
  337. if (pcb->_pvAddr == pvAddr)
  338. {
  339. if (pcb->_pcbPrev)
  340. pcb->_pcbPrev->_pcbNext = pcb->_pcbNext;
  341. else
  342. pcbChkBlocks = pcb->_pcbNext;
  343. if (pcb->_pcbNext)
  344. pcb->_pcbNext->_pcbPrev = pcb->_pcbPrev;
  345. delete pcb;
  346. return;
  347. }
  348. }
  349. //+--------------------------------------------------------------
  350. //
  351. // Function: DbgFreeChkBlocks, private
  352. //
  353. // Synopsis: Frees all checksum blocks
  354. //
  355. // History: 08-Apr-92 DrewB Created
  356. //
  357. //---------------------------------------------------------------
  358. void DbgFreeChkBlocks(void)
  359. {
  360. CChecksumBlock *pcb;
  361. while (pcbChkBlocks)
  362. {
  363. pcb = pcbChkBlocks->_pcbNext;
  364. delete pcbChkBlocks;
  365. pcbChkBlocks = pcb;
  366. }
  367. }
  368. static CGlobalFileStream *g_pDebugLogGlobalFileStream = NULL;
  369. inline CGlobalFileStream *GetGlobalFileStream()
  370. {
  371. return g_pDebugLogGlobalFileStream;
  372. }
  373. inline void SetGlobalFileStream(CGlobalFileStream *pgfst)
  374. {
  375. g_pDebugLogGlobalFileStream = pgfst;
  376. }
  377. #ifdef MULTIHEAP
  378. static CFileStream *g_pDebugLogFileStream = NULL;
  379. #endif
  380. SCODE GetLogFile(CFileStream **pfs)
  381. #ifdef MULTIHEAP
  382. {
  383. // Do not use shared memory to write log files
  384. SCODE sc = S_OK;
  385. if (GetGlobalFileStream() == NULL)
  386. {
  387. g_pDebugLogGlobalFileStream = ::new CGlobalFileStream
  388. (NULL, 0, LOGFILEDFFLAGS, LOGFILESTARTFLAGS);
  389. SetGlobalFileStream (g_pDebugLogGlobalFileStream);
  390. g_pDebugLogFileStream = ::new CFileStream (NULL);
  391. }
  392. g_pDebugLogFileStream->InitFromGlobal(GetGlobalFileStream());
  393. *pfs = g_pDebugLogFileStream;
  394. return sc;
  395. }
  396. #else
  397. {
  398. SCODE sc = S_OK;
  399. CFileStream *pfsLoop = NULL;
  400. *pfs = NULL;
  401. if (GetGlobalFileStream() == NULL)
  402. {
  403. IMalloc *pMalloc;
  404. olHChk(DfCreateSharedAllocator(&pMalloc));
  405. SetGlobalFileStream(new (pMalloc) CGlobalFileStream(pMalloc,
  406. 0, LOGFILEDFFLAGS,
  407. LOGFILESTARTFLAGS));
  408. pMalloc->Release();
  409. }
  410. if (GetGlobalFileStream() != NULL)
  411. {
  412. pfsLoop = GetGlobalFileStream()->Find(GetCurrentContextId());
  413. if (pfsLoop == NULL)
  414. {
  415. IMalloc *pMalloc;
  416. olHChk(DfCreateSharedAllocator(&pMalloc));
  417. pfsLoop = new (pMalloc) CFileStream(pMalloc);
  418. pMalloc->Release();
  419. if (pfsLoop != NULL)
  420. pfsLoop->InitFromGlobal(GetGlobalFileStream());
  421. }
  422. }
  423. EH_Err:
  424. *pfs = pfsLoop;
  425. return sc;
  426. }
  427. #endif // MULIHEAP
  428. SCODE _FreeLogFile(void)
  429. {
  430. #ifdef MULTIHEAP
  431. if (GetGlobalFileStream())
  432. {
  433. g_pDebugLogFileStream->RemoveFromGlobal();
  434. memset (g_pDebugLogGlobalFileStream, 0, sizeof(CContextList));
  435. ::delete g_pDebugLogFileStream;
  436. ::delete g_pDebugLogGlobalFileStream;
  437. SetGlobalFileStream (NULL);
  438. }
  439. return S_OK;
  440. #else
  441. CFileStream *pfsLoop = NULL;
  442. if (GetGlobalFileStream())
  443. pfsLoop = GetGlobalFileStream()->Find(GetCurrentContextId());
  444. if (pfsLoop != NULL)
  445. {
  446. pfsLoop->vRelease();
  447. GetGlobalFileStream()->Release();
  448. SetGlobalFileStream(NULL);
  449. return S_OK;
  450. }
  451. return STG_E_UNKNOWN;
  452. #endif
  453. }
  454. long cLogNestings = 0;
  455. void OutputLogfileMessage(char const *format, ...)
  456. {
  457. int length;
  458. char achPreFormat[] = "PID[%lx] TID[%lx] ";
  459. char achBuffer[256];
  460. ULONG cbWritten;
  461. CFileStream *pfs = NULL;
  462. va_list arglist;
  463. STATSTG stat;
  464. if (cLogNestings > 0)
  465. return;
  466. TAKEMTX;
  467. cLogNestings++;
  468. va_start(arglist, format);
  469. GetLogFile(&pfs);
  470. if (NULL != pfs)
  471. {
  472. pfs->InitFile(gwcsLogFile);
  473. pfs->Stat(&stat, STATFLAG_NONAME);
  474. if (DfGetResLimit(DBRF_LOGGING) & DFLOG_PIDTID)
  475. {
  476. // Prepare prefix string
  477. length = wsprintfA(achBuffer, "PID[%8lx] TID[%8lx] ",
  478. GetCurrentProcessId(), GetCurrentThreadId());
  479. // length does not include NULL terminator
  480. pfs->WriteAt(stat.cbSize, achBuffer, length, &cbWritten);
  481. stat.cbSize.LowPart += cbWritten;
  482. }
  483. // Write caller data to logfile
  484. #if WIN32 == 300
  485. wsprintfA(achBuffer, format, arglist);
  486. #else
  487. wsprintfA(achBuffer, format, arglist);
  488. #endif
  489. length = strlen(achBuffer);
  490. for (int i = 0; i < length; i++)
  491. {
  492. if (((achBuffer[i] < 32) || (achBuffer[i] > 127)) &&
  493. (achBuffer[i] != '\n') && (achBuffer[i] != '\t'))
  494. {
  495. achBuffer[i] = '.';
  496. }
  497. }
  498. pfs->WriteAt(stat.cbSize, achBuffer, length, &cbWritten);
  499. }
  500. cLogNestings--;
  501. RELEASEMTX;
  502. }
  503. #endif // DBG == 1