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.

813 lines
20 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 - 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dndbg.c
  6. * Content: debug support for DirectNet
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 05-20-99 aarono Created
  12. * 07-16-99 johnkan Fixed include of OSInd.h, defined WSPRINTF macro
  13. * 07-19-99 vanceo Explicitly declared OutStr as returning void for NT
  14. * Build environment.
  15. * 07-22-99 a-evsch Check for multiple Inits, and release CritSec when DebugPrintf
  16. * returns early.
  17. * 08-02-99 a-evsch Added LOGPF support. LW entries only go into shared-file log
  18. * 08-31-99 johnkan Removed include of <OSIND.H>
  19. * 09/01/99 rodtoll Added functions to check valid read/write pointers
  20. * 01-10-00 pnewson Added support for logging to disk
  21. *
  22. * Notes:
  23. *
  24. * Use /Oi compiler option for strlen()
  25. *
  26. ***************************************************************************/
  27. #if defined(DEBUG) || defined(DBG)
  28. #include <windows.h>
  29. #include "memlog.h"
  30. #include "dndbg.h"
  31. //===============
  32. // Debug support
  33. //===============
  34. /*******************************************************************************
  35. Debug Logging to VXD. In order to get this logging, DNET.VXD must be
  36. installed on the system. This service is only available in the Win9x code
  37. base and can be installed by added the following to the system.ini file
  38. in the 386Enh section
  39. [386Enh]
  40. device=dnet.vxd
  41. This will enable a set of command under the debugger for dumping the
  42. log when broken into the debugger. The commands can be initiated by
  43. typing .dnet at the ## prompt in the debugger.
  44. ==============================================================================*/
  45. /*
  46. BOOL DeviceIoControl(
  47. HANDLE hDevice, // handle to device of interest
  48. DWORD dwIoControlCode, // control code of operation to perform
  49. LPVOID lpInBuffer, // pointer to buffer to supply input data
  50. DWORD nInBufferSize, // size of input buffer
  51. LPVOID lpOutBuffer, // pointer to buffer to receive output data
  52. DWORD nOutBufferSize, // size of output buffer
  53. LPDWORD lpBytesReturned, // pointer to variable to receive output byte count
  54. LPOVERLAPPED lpOverlapped // pointer to overlapped structure for asynchronous operation
  55. );
  56. */
  57. #define MAX_STRING 240
  58. #define LOG_SIZE 2000
  59. #define FIRST_DEBUG_PROC 100
  60. #define OPEN_DEBUGLOG (FIRST_DEBUG_PROC)
  61. #define WRITE_DEBUGLOG (FIRST_DEBUG_PROC+1)
  62. #define WRITE_STATS (FIRST_DEBUG_PROC+2)
  63. #define WSPRINTF wsprintfA
  64. typedef struct _LOGENTRY {
  65. CHAR debuglevel;
  66. CHAR str[1];
  67. } LOGENTRY, *PLOGENTRY;
  68. typedef struct {
  69. UINT nLogEntries;
  70. UINT nCharsPerLine;
  71. } IN_LOGINIT, *PIN_LOGINIT;
  72. typedef struct {
  73. UINT hr;
  74. } OUT_LOGINIT, *POUT_LOGINIT;
  75. typedef struct {
  76. CHAR debuglevel;
  77. CHAR str[1];
  78. } IN_LOGWRITE, *PIN_LOGWRITE;
  79. typedef struct {
  80. UINT hr;
  81. } OUT_LOGWRITE, *POUT_LOGWRITE;
  82. HANDLE hLoggingVxd=0;
  83. HANDLE hLogMutex=0;
  84. HANDLE hLogFile=0;
  85. PSHARED_LOG_FILE pLogFile=0;
  86. char szDiskFileName[MAX_PATH+1];
  87. HANDLE hDiskFile=0;
  88. HANDLE hDiskMutex=0;
  89. #define DISK_LOG_MUTEX_NAME "DPLAYLOGMUTEX-1"
  90. /*===========================================================================
  91. Debug Support.
  92. Logging:
  93. ========
  94. Debug Logging and playback is designed to operate on both Win9x and
  95. Windows NT (Windows 2000). On Win9x, a support VXD is used to extend
  96. the kernel debugger. The VXD (DNET.VXD) is used for both logging and
  97. playback of debug buffers. In addition to the debug VXD there is also
  98. logging to a shared file. The shared file logging is played back with
  99. the DNLOG.EXE utility and can be played back on either Windows2000 or
  100. Win9x.
  101. Debug support for dumping structures on Win9x is supported only in the
  102. DNET.VXD component. Dumping of structures internal to DPLAY can only
  103. be done from the context of a DPLAY thread. This is because the
  104. addresses are only valid in that context. Under NT there is (will be)
  105. a debug extension for dumping internal structures.
  106. Debug Logging is controlled by settings in the win.ini file. Under
  107. the section heading [DirectNet]. There are 2 settings:
  108. Debug=9
  109. controls the debug level. All messages, at or below that debug level
  110. are printed.
  111. The second setting (logging). If not specified, all debugs are spewed
  112. through the standard DebugPrint and will appear on in DEVSTUDIO if
  113. it is up, or on the kernel debugger if it is running.
  114. This is a bit mask.
  115. bit 1 - spew to console
  116. bit 2 - spew to memory and vxd log
  117. bit 3 - spew to a disk file
  118. therefore:
  119. log = 0 {no debug output}
  120. log = 1 {spew to console only}
  121. log = 2 {spew to log only}
  122. log = 3 {spew to console and log}
  123. log = 4 {spew to disk}
  124. log = 5 {spew to console and disk}
  125. log = 6 {spew to log and disk}
  126. log = 7 {spew to console, log and disk}
  127. example win.ini...
  128. Use the "FileName" key to set the disk file that disk spew
  129. is written to. Data will be appended to this file. You must
  130. delete it yourself to keep it from growing without bound.
  131. This is so that if multiple concurrent processes call DPF_INIT()
  132. they will not delete the log written to that point.
  133. [DirectNet]
  134. Debug=7 ; lots of spew
  135. log=6 ; don't spew to debug window, but to log and disk
  136. FileName=c:\dplog.txt ; spew to the disk file c:\dplog.txt
  137. [DirectNet]
  138. Debug=0 ; only fatal errors spewed to debug window
  139. Asserts:
  140. ========
  141. Asserts are used to validate assumptions in the code. For example
  142. if you know that the variable jojo should be > 700 and are depending
  143. on it in subsequent code, you SHOULD put an assert before the code
  144. that acts on that assumption. The assert would look like:
  145. ASSERT(jojo>700);
  146. Asserts generally will produce 3 lines of debug spew to highlight the
  147. breaking of the assumption. For testing, you might want to set the
  148. system to break in on asserts. This is done in the [DirectNet] section
  149. of win.ini by setting BreakOnAssert=TRUE
  150. e.g.
  151. [DirectNet]
  152. Debug=0
  153. BreakOnAssert=TRUE
  154. Verbose=1
  155. Debug Breaks:
  156. =============
  157. When something really severe happens and you want the system to break in
  158. so that you can debug it later, you should put a debug break in the code
  159. path. Some people use the philosophy that all code paths must be
  160. verified by hand tracing each one in the debugger. If you abide by this
  161. you should place a DEBUG_BREAK() in every code path and remove them
  162. from the source as you trace each. When you have good coverage but
  163. some unhit paths (error conditions) you should force those paths in
  164. the debugger.
  165. ===========================================================================*/
  166. BOOL bInited=FALSE;
  167. static CRITICAL_SECTION csDPF;
  168. DWORD lDebugLevel = 0;
  169. DWORD dwLogging = 1; // 0 => No debug spew
  170. // 1 => Spew to console only (default)
  171. // 2 => Spew to log only
  172. // 3 => Spew to console and log
  173. DWORD bBreakOnAssert=FALSE; // if TRUE, causes DEBUG_BREAK on false asserts.
  174. // if TRUE, all file/line/module information is printed and logged.
  175. DWORD nVerboseLevel = 0; // 1 => very verbose
  176. // 2 => Newson verbose
  177. BOOL bLiveLogging = FALSE;
  178. // if TRUE messages printed with the LOGPF will be logged, if FALSE they're ignored
  179. DWORD lOutputLog = 0;
  180. // Informational variables set for DebugPrintf before actual call
  181. // to do printing/logging. These variables are locked by csDPF
  182. // when set. csDPF is dropped when the data is finally printed
  183. // which means there must be a call to DebugSetLineInfo followed
  184. // immediately by a call to DebugPrintf. This is hidden by the
  185. // DPF macro.
  186. static DWORD g_dwLine; // line number of current DPF
  187. static char g_szFile [ MAX_PATH ]; // file name of current DPF
  188. static char g_szModName [ MAX_PATH ]; // module name of current DPF
  189. // mystrncpy -
  190. // our own strncpy to avoid linking CLIB. This is debug only and hence
  191. // not time critical, so this simple routine is fine.
  192. // note: strlen also in this module is a Generic Intrinsic fn, so this
  193. // module should be compiled /Oi.
  194. void mystrncpy(char * to,char * from,int n)
  195. {
  196. for(;n;n--)
  197. *(to++)=*(from++);
  198. }
  199. // open up a channel to the DirectNet VXD (DNET.VXD) that will allows
  200. // the log to be written to the VxD through DeviceIoControl calls. The
  201. // log in this case is accessible in the Win9x kernel debugger through
  202. // the .dnet debugger extensions.
  203. void InitDirectNetVxd(void)
  204. {
  205. IN_LOGINIT In;
  206. OUT_LOGINIT Out;
  207. UINT cbRet;
  208. // note we rely on the system automatically closing this
  209. // handle for us when the user mode application exits.
  210. hLoggingVxd = CreateFileA("\\\\.\\DNET",0,0,0,0,0,0);
  211. if(hLoggingVxd != INVALID_HANDLE_VALUE){
  212. In.nCharsPerLine=MAX_STRING;
  213. In.nLogEntries=5000;
  214. DeviceIoControl(hLoggingVxd,
  215. OPEN_DEBUGLOG,
  216. &In,sizeof(In),
  217. &Out, sizeof(Out),
  218. &cbRet, NULL);
  219. } else {
  220. hLoggingVxd=0;
  221. }
  222. }
  223. // Write a string to the log in the debug support VxD. This only
  224. // operates on Win9x, when the DNET.VXD is installed.
  225. static void VxdLogString( LPSTR str )
  226. {
  227. char logstring[MAX_STRING+sizeof(LOGENTRY)];
  228. int i=0;
  229. PLOGENTRY pLogEntry=(PLOGENTRY)&logstring;
  230. UINT rc;
  231. UINT cbRet;
  232. int maxlen = MAX_STRING+sizeof(LOGENTRY);
  233. if(hLoggingVxd && str){
  234. while(str[i] && i < maxlen)
  235. i++;
  236. pLogEntry->debuglevel=0;
  237. memcpy(pLogEntry->str,str,i+1);
  238. DeviceIoControl(hLoggingVxd,WRITE_DEBUGLOG,pLogEntry,i+sizeof(LOGENTRY), &rc, sizeof(rc), &cbRet, NULL);
  239. }
  240. }
  241. // Create a shared file for logging information on the fly
  242. // This support allows the current log to be dumped from the
  243. // user mode DPLOG.EXE application. This is useful when debugging
  244. // in MSSTUDIO or in NTSD. When the DPLOG.EXE is invoke, note that
  245. // the application will get halted until the log is completely dumped
  246. // so it is best to dump the log to a file.
  247. static BOOL InitMemLogString(VOID)
  248. {
  249. static BOOL inited = FALSE;
  250. if(!inited){
  251. hLogFile=CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, DPLOG_SIZE, BASE_LOG_FILENAME);
  252. hLogMutex=CreateMutexA(NULL,FALSE,BASE_LOG_MUTEXNAME);
  253. pLogFile=(PSHARED_LOG_FILE)MapViewOfFile(hLogFile, FILE_MAP_ALL_ACCESS,0,0,0);
  254. if(!hLogFile || !hLogMutex || !pLogFile){
  255. if(hLogFile){
  256. CloseHandle(hLogFile);
  257. hLogFile=0;
  258. }
  259. if(hLogMutex){
  260. CloseHandle(hLogMutex);
  261. hLogMutex=0;
  262. }
  263. if(pLogFile){
  264. UnmapViewOfFile(pLogFile);
  265. pLogFile=NULL;
  266. }
  267. return FALSE;
  268. } else {
  269. inited = TRUE;
  270. pLogFile->nEntries = DPLOG_NUMENTRIES;
  271. pLogFile->cbLine = DPLOG_ENTRYSIZE;
  272. pLogFile->iWrite = 0;
  273. pLogFile->cInUse = 0;
  274. }
  275. }
  276. return TRUE;
  277. }
  278. // open a disk file to receive spew
  279. static BOOL InitDiskLogString(VOID)
  280. {
  281. static BOOL inited = FALSE;
  282. if(!inited){
  283. // we're relying on the system to clean up these
  284. // handles when the process exits
  285. hDiskFile = CreateFileA(szDiskFileName,
  286. GENERIC_WRITE,
  287. FILE_SHARE_READ|FILE_SHARE_WRITE,
  288. NULL,
  289. OPEN_ALWAYS,
  290. FILE_ATTRIBUTE_NORMAL,
  291. NULL);
  292. hDiskMutex=CreateMutexA(NULL,FALSE,DISK_LOG_MUTEX_NAME);
  293. if(!hDiskFile || !hDiskMutex){
  294. if(hDiskFile){
  295. CloseHandle(hDiskFile);
  296. hDiskFile=0;
  297. }
  298. if(hDiskMutex){
  299. CloseHandle(hDiskMutex);
  300. hDiskMutex=0;
  301. }
  302. return FALSE;
  303. } else {
  304. inited = TRUE;
  305. }
  306. }
  307. return TRUE;
  308. }
  309. // Log a string to a shared file. This file can be dumped using the
  310. // DPLOG.EXE utility.
  311. static void MemLogString(LPSTR str)
  312. {
  313. PLOG_ENTRY pEntry;
  314. DWORD cbCopy;
  315. if(!hLogFile){
  316. if(!InitMemLogString()){
  317. return;
  318. }
  319. }
  320. WaitForSingleObject(hLogMutex,INFINITE);
  321. pEntry=(PLOG_ENTRY)(((PUCHAR)(pLogFile+1))+(pLogFile->iWrite*(sizeof(LOG_ENTRY)+DPLOG_ENTRYSIZE)));
  322. pEntry->hThread=GetCurrentThreadId();
  323. pEntry->tLogged=timeGetTime();
  324. pEntry->DebugLevel=0;
  325. cbCopy=strlen(str)+1;
  326. if(cbCopy > DPLOG_ENTRYSIZE){
  327. str[DPLOG_ENTRYSIZE]=0;
  328. cbCopy=DPLOG_ENTRYSIZE;
  329. }
  330. memcpy(pEntry->str, str, cbCopy);
  331. if(pLogFile->iWrite+1 > pLogFile->cInUse){
  332. pLogFile->cInUse=pLogFile->iWrite+1;
  333. }
  334. pLogFile->iWrite = (pLogFile->iWrite+1) % pLogFile->nEntries;
  335. ReleaseMutex(hLogMutex);
  336. }
  337. // Log the string to an ordinary disk file
  338. static void DiskLogString(LPSTR str)
  339. {
  340. DWORD dwBytesWritten;
  341. if(!hDiskFile){
  342. if(!InitDiskLogString()){
  343. return;
  344. }
  345. }
  346. WaitForSingleObject(hDiskMutex,INFINITE);
  347. if (SetFilePointer(hDiskFile, 0, NULL, FILE_END) != INVALID_SET_FILE_POINTER)
  348. {
  349. WriteFile(hDiskFile, str, strlen(str), &dwBytesWritten, NULL);
  350. WriteFile(hDiskFile, "\r\n", strlen("\r\n"), &dwBytesWritten, NULL);
  351. FlushFileBuffers(hDiskFile);
  352. }
  353. ReleaseMutex(hDiskMutex);
  354. }
  355. // DebugPrintfInit() - initialize DPF support.
  356. void DebugPrintfInit()
  357. {
  358. DWORD lSpecificLevel;
  359. if(bInited == TRUE){ // DPF deadlocks if it gets inited twice.
  360. return;
  361. }
  362. lDebugLevel = (signed int) GetProfileIntA( PROF_SECT, "debug", 0 );
  363. lSpecificLevel = (signed int) GetProfileIntA( PROF_SECT, DPF_MODULE_NAME, -1);
  364. if(lSpecificLevel != -1){
  365. lDebugLevel = lSpecificLevel;
  366. }
  367. dwLogging = (signed int) GetProfileIntA( PROF_SECT, "log" , 0);
  368. bBreakOnAssert = (signed int) GetProfileIntA( PROF_SECT, "BreakOnAssert", 0);
  369. nVerboseLevel = (signed int) GetProfileIntA( PROF_SECT, "Verbose", 0);
  370. lOutputLog = (signed int) GetProfileIntA( PROF_SECT, "OutputLog", 0);
  371. ZeroMemory(szDiskFileName, MAX_PATH+1);
  372. GetProfileStringA(PROF_SECT, "FileName", "C:\\dplog.txt", szDiskFileName, MAX_PATH+1);
  373. if (dwLogging & 0x0001)
  374. {
  375. bLiveLogging=TRUE;
  376. }
  377. else
  378. {
  379. bLiveLogging=FALSE;
  380. }
  381. /*
  382. switch(dwLogging){
  383. case 0:
  384. bLiveLogging=FALSE;
  385. break;
  386. case 1:
  387. bLiveLogging=TRUE;
  388. break;
  389. case 2:
  390. bLiveLogging=FALSE;
  391. break;
  392. case 3:
  393. bLiveLogging=TRUE;
  394. break;
  395. default:
  396. break;
  397. }
  398. */
  399. if((dwLogging & 0x0002)||(lOutputLog > 0)){
  400. // Doing log based logging, so try to find the VXD and open
  401. // the shared logging file.
  402. InitDirectNetVxd();
  403. // Do logging also based on shared memory file.
  404. InitMemLogString();
  405. }
  406. if (dwLogging & 0x0004)
  407. {
  408. // We're also logging to a file, open it
  409. InitDiskLogString();
  410. }
  411. InitializeCriticalSection(&csDPF);
  412. bInited=TRUE;
  413. }
  414. // DebugPrintfFini() - release resources used by DPF support.
  415. void DebugPrintfFini()
  416. {
  417. if(hLogFile){
  418. CloseHandle(hLogFile);
  419. }
  420. if(hLoggingVxd){
  421. CloseHandle(hLoggingVxd);
  422. }
  423. DeleteCriticalSection(&csDPF);
  424. bInited = FALSE;
  425. }
  426. // DebugSetLineInfo - store information about where the DPF is from.
  427. //
  428. // Called before a call to DebugPrintf in order to specify the file
  429. // line and function from which the DPF is being called. This allows
  430. // logging of these values. In order to support this though, the
  431. // values are stored in globals over the duration of the call, so a
  432. // lock is acquired in this call and released in the DebugPrintf call.
  433. // This means these functions MUST be called one after the other.
  434. void DebugSetLineInfo(LPSTR szFile, DWORD dwLine, LPSTR szModName)
  435. {
  436. if(!bInited){
  437. // NOTE: your module should call DPFINIT() if possible.
  438. DebugPrintfInit();
  439. }
  440. EnterCriticalSection(&csDPF);
  441. mystrncpy (g_szFile,szFile,sizeof(g_szFile));
  442. mystrncpy (g_szModName,szModName,sizeof(g_szModName));
  443. g_dwLine = dwLine;
  444. }
  445. // Actually ouput the string to the various output methods as requested
  446. // in the win.ini section.
  447. void OutStr( DWORD dwDetail, LPSTR str )
  448. {
  449. INT i=0;
  450. if(dwDetail <= lDebugLevel){
  451. if(str)while(str[i++]); // string warming
  452. if(bLiveLogging)
  453. {
  454. // log to debugger output
  455. OutputDebugStringA(str);
  456. OutputDebugStringA("\n");
  457. }
  458. if(hLoggingVxd){
  459. // log to vxd
  460. VxdLogString( str );
  461. }
  462. if(dwLogging & 0x0002){
  463. // log to shared file
  464. MemLogString( str );
  465. }
  466. if(dwLogging & 0x0004){
  467. // log to shared file
  468. DiskLogString( str );
  469. }
  470. }
  471. }
  472. void DebugPrintfNoLock(volatile DWORD dwDetail, ...){
  473. CHAR cMsg[1000];
  474. LPSTR szFormat;
  475. va_list argptr;
  476. if(!bInited){
  477. // NOTE: your module should call DPFINIT() if possible.
  478. DebugPrintfInit();
  479. }
  480. if(lDebugLevel < dwDetail)
  481. return;
  482. va_start(argptr, dwDetail);
  483. szFormat = (LPSTR)(DWORD_PTR)va_arg(argptr, DWORD);
  484. cMsg[0]=0;
  485. // Prints out / logs as:
  486. // 1. Verbose
  487. // dwDetail:ThreadId:File:Fn:Line:DebugString
  488. // e.g.
  489. // 2:8007eaf:DPLAYX.DLL:DPOS.C(L213):
  490. //
  491. // 2. Regular
  492. // ThreadId:DebugString
  493. WSPRINTF(cMsg,"%1d:",dwDetail);
  494. WSPRINTF(cMsg+strlen(cMsg),"%08x:",GetCurrentThreadId());
  495. if(nVerboseLevel==1){
  496. WSPRINTF(cMsg+strlen(cMsg),"(%12s)",g_szFile);
  497. WSPRINTF(cMsg+strlen(cMsg),"%s",g_szModName);
  498. WSPRINTF(cMsg+strlen(cMsg),"(L%d)",g_dwLine);
  499. } else if (nVerboseLevel==2){
  500. WSPRINTF(cMsg+strlen(cMsg),"%s",g_szModName);
  501. WSPRINTF(cMsg+strlen(cMsg),"(L%d)",g_dwLine);
  502. }
  503. WSPRINTF(cMsg+lstrlenA( cMsg ), szFormat, argptr);
  504. OutStr( dwDetail, cMsg );
  505. va_end(argptr);
  506. }
  507. // DebugPrintf - print a debug string
  508. //
  509. // You must call DebugSetLineInfo before making this call.
  510. //
  511. void DebugPrintf(volatile DWORD dwDetail, ...)
  512. {
  513. CHAR cMsg[1000];
  514. LPSTR szFormat;
  515. va_list argptr;
  516. if(!bInited){
  517. // NOTE: your module should call DPFINIT() if possible.
  518. DebugPrintfInit();
  519. }
  520. if(lDebugLevel < dwDetail){
  521. LeaveCriticalSection(&csDPF);
  522. return;
  523. }
  524. va_start(argptr, dwDetail);
  525. szFormat = (LPSTR)(DWORD_PTR)va_arg(argptr, DWORD);
  526. cMsg[0]=0;
  527. // Prints out / logs as:
  528. // 1. Verbose
  529. // dwDetail:ThreadId:File:Fn:Line:DebugString
  530. // e.g.
  531. // 2:8007eaf:DPLAYX.DLL:DPOS.C(L213):
  532. //
  533. // 2. Regular
  534. // ThreadId:DebugString
  535. WSPRINTF(cMsg,"%1d:",dwDetail);
  536. WSPRINTF(cMsg+strlen(cMsg),"%08x:",GetCurrentThreadId());
  537. if(nVerboseLevel==1){
  538. WSPRINTF(cMsg+strlen(cMsg),"(%12s)",g_szFile);
  539. WSPRINTF(cMsg+strlen(cMsg),"%s",g_szModName);
  540. WSPRINTF(cMsg+strlen(cMsg),"(L%d)",g_dwLine);
  541. } else if (nVerboseLevel==2){
  542. WSPRINTF(cMsg+strlen(cMsg),"%s",g_szModName);
  543. WSPRINTF(cMsg+strlen(cMsg),"(L%d)",g_dwLine);
  544. }
  545. WVSPRINTF(cMsg+lstrlenA( cMsg ), szFormat, argptr);
  546. OutStr( dwDetail, cMsg );
  547. LeaveCriticalSection(&csDPF);
  548. va_end(argptr);
  549. }
  550. /*
  551. ** LogPrintf copies a quick Log Entry to the
  552. **
  553. */
  554. void LogPrintf(volatile DWORD dwDetail, ...)
  555. {
  556. CHAR cMsg[1000];
  557. LPSTR szFormat;
  558. va_list argptr;
  559. if(lOutputLog < dwDetail){
  560. return;
  561. }
  562. EnterCriticalSection(&csDPF);
  563. va_start(argptr, dwDetail);
  564. szFormat = (LPSTR)(DWORD_PTR)va_arg(argptr, DWORD);
  565. cMsg[0]=0;
  566. WSPRINTF(cMsg,"%s: ",g_szModName);
  567. WVSPRINTF(cMsg+lstrlenA( cMsg ), szFormat, argptr);
  568. MemLogString( (LPSTR) cMsg );
  569. LeaveCriticalSection(&csDPF);
  570. va_end(argptr);
  571. }
  572. //
  573. // NOTE: I don't want to get into error checking for buffer overflows when
  574. // trying to issue an assertion failure message. So instead I just allocate
  575. // a buffer that is "bug enough" (I know, I know...)
  576. //
  577. #define ASSERT_BUFFER_SIZE 512
  578. #define ASSERT_BANNER_STRING "************************************************************"
  579. #define ASSERT_BREAK_SECTION "BreakOnAssert"
  580. #define ASSERT_BREAK_DEFAULT FALSE
  581. #define ASSERT_MESSAGE_LEVEL 0
  582. void _DNAssert( LPCSTR szFile, int nLine, LPCSTR szCondition )
  583. {
  584. char buffer[ASSERT_BUFFER_SIZE];
  585. /*
  586. * Build the debug stream message.
  587. */
  588. WSPRINTF( buffer, "ASSERTION FAILED! File %s Line %d: %s", szFile, nLine, szCondition );
  589. /*
  590. * Actually issue the message. These messages are considered error level
  591. * so they all go out at error level priority.
  592. */
  593. dprintf( ASSERT_MESSAGE_LEVEL, ASSERT_BANNER_STRING );
  594. dprintf( ASSERT_MESSAGE_LEVEL, buffer );
  595. dprintf( ASSERT_MESSAGE_LEVEL, ASSERT_BANNER_STRING );
  596. /*
  597. * Should we drop into the debugger?
  598. */
  599. if( bBreakOnAssert || GetProfileIntA( PROF_SECT, ASSERT_BREAK_SECTION, ASSERT_BREAK_DEFAULT ) )
  600. {
  601. /*
  602. * Into the debugger we go...
  603. */
  604. DEBUG_BREAK();
  605. }
  606. }
  607. // IsValidWritePtr
  608. //
  609. // Checks to ensure memory pointed to by the buffer is valid for
  610. // writing dwSize bytes. Contents of the memory are restored
  611. // after this call.
  612. //
  613. BOOL IsValidWritePtr( LPVOID lpBuffer, DWORD dwSize )
  614. {
  615. DWORD dwIndex;
  616. BYTE bTempValue;
  617. LPBYTE lpBufferPtr = (LPBYTE) lpBuffer;
  618. if( lpBuffer == NULL )
  619. return FALSE;
  620. _try
  621. {
  622. for( dwIndex = 0; dwIndex < dwSize; dwIndex++ )
  623. {
  624. bTempValue = lpBufferPtr[dwIndex];
  625. lpBufferPtr[dwIndex] = 0xcc;
  626. lpBufferPtr[dwIndex] = bTempValue;
  627. }
  628. }
  629. _except( EXCEPTION_EXECUTE_HANDLER )
  630. {
  631. return FALSE;
  632. }
  633. return TRUE;
  634. }
  635. // IsValidReadPtr
  636. //
  637. // Checks to see if the memory pointed to by lpBuffer is valid for
  638. // reading of dwSize bytes.
  639. //
  640. BOOL IsValidReadPtr( LPVOID lpBuffer, DWORD dwSize )
  641. {
  642. DWORD dwIndex;
  643. BYTE bTempValue;
  644. LPBYTE lpBufferPtr = (LPBYTE) lpBuffer;
  645. DWORD dwTotal = 0;
  646. if( lpBuffer == NULL )
  647. return FALSE;
  648. _try
  649. {
  650. for( dwIndex = 0; dwIndex < dwSize; dwIndex++ )
  651. {
  652. bTempValue = lpBufferPtr[dwIndex];
  653. dwTotal += bTempValue;
  654. }
  655. }
  656. _except( EXCEPTION_EXECUTE_HANDLER )
  657. {
  658. return FALSE;
  659. }
  660. return TRUE;
  661. }
  662. #endif //defined debug