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.

673 lines
17 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: newdpf.c
  6. * Content: new debug printf
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 10-oct-95 jeffno initial implementation
  12. * 6/10/98 a-peterz Check CreateFile() result against INVALID_HANDLE_VALUE
  13. *@@END_MSINTERNAL
  14. *
  15. ***************************************************************************/
  16. #if defined(DEBUG) || defined(DBG)
  17. #ifdef IS_16
  18. #define OUTPUTDEBUGSTRING OutputDebugString
  19. #define GETPROFILESTRING GetProfileString
  20. #define GETPROFILEINT GetProfileInt
  21. #define WSPRINTF wsprintf
  22. #define WVSPRINTF wvsprintf
  23. #define LSTRLEN lstrlen
  24. #else
  25. #define OUTPUTDEBUGSTRING OutputDebugStringA
  26. #define GETPROFILESTRING GetProfileStringA
  27. #define GETPROFILEINT GetProfileIntA
  28. #define WSPRINTF wsprintfA
  29. #define WVSPRINTF wvsprintfA
  30. #define LSTRLEN lstrlenA
  31. #endif
  32. #include "newdpf.h"
  33. #undef DEBUG_TOPIC
  34. #define DEBUG_TOPIC(flag,name) {#flag,name,TRUE},
  35. static
  36. struct {
  37. char cFlag[4];
  38. char cName[64];
  39. BOOL bOn;
  40. } DebugTopics[] = {
  41. {"","Filler",FALSE},
  42. {"A","API Usage",TRUE},
  43. #include "DBGTOPIC.H"
  44. {"","End",FALSE}
  45. };
  46. #ifndef DPF_MODULE_NAME
  47. #define DPF_MODULE_NAME ""
  48. #endif
  49. static DWORD bDetailOn = 1;
  50. static BOOL bInited=FALSE;
  51. static BOOL bAllowMisc=TRUE;
  52. static bBreakOnAsserts=FALSE;
  53. static bPrintLineNumbers=FALSE;
  54. static bPrintFileNames=FALSE;
  55. static bPrintExecutableName=FALSE;
  56. static bPrintTID=FALSE;
  57. static bPrintPID=FALSE;
  58. static bIndentOnMessageLevel=FALSE;
  59. static bPrintTopicsAndLevels=FALSE;
  60. static bPrintModuleName=TRUE;
  61. static bPrintFunctionName=FALSE;
  62. static bRespectColumns=FALSE;
  63. static bPrintAPIStats=FALSE;
  64. static bPrintAllTopics=TRUE;
  65. static DWORD dwFileLineTID=0;
  66. static char cFile[100];
  67. static char cFnName[100];
  68. static DWORD dwLineNo;
  69. static bMute=FALSE;
  70. static BOOL bLogging=FALSE; // whether to use the logging VxD instead of dumping.
  71. DPF_PROC_STATS ProcStats[MAX_PROC_ORDINAL];
  72. #ifdef cplusplus
  73. extern "C" {
  74. #endif
  75. void mystrncpy(char * to,char * from,int n)
  76. {
  77. for(;n;n--)
  78. *(to++)=*(from++);
  79. }
  80. char * mystrrchr(char * in,char c)
  81. {
  82. char * last=0;
  83. while (*in)
  84. {
  85. if (*in == c)
  86. last = in;
  87. in++;
  88. }
  89. return last;
  90. }
  91. char Junk[]="DPF_MODNAME undef'd";
  92. char * DPF_MODNAME = Junk;
  93. int DebugSetFileLineEtc(LPSTR szFile, DWORD dwLineNumber, LPSTR szFnName)
  94. {
  95. if (!(bPrintFileNames||bPrintLineNumbers||bPrintFunctionName))
  96. {
  97. return 1;
  98. }
  99. #ifdef WIN32
  100. dwFileLineTID = GetCurrentThreadId();
  101. #endif
  102. mystrncpy (cFile,szFile,sizeof(cFile));
  103. mystrncpy (cFnName,szFnName,sizeof(cFnName));
  104. dwLineNo = dwLineNumber;
  105. return 1;
  106. }
  107. /*
  108. BOOL DeviceIoControl(
  109. HANDLE hDevice, // handle to device of interest
  110. DWORD dwIoControlCode, // control code of operation to perform
  111. LPVOID lpInBuffer, // pointer to buffer to supply input data
  112. DWORD nInBufferSize, // size of input buffer
  113. LPVOID lpOutBuffer, // pointer to buffer to receive output data
  114. DWORD nOutBufferSize, // size of output buffer
  115. LPDWORD lpBytesReturned, // pointer to variable to receive output byte count
  116. LPOVERLAPPED lpOverlapped // pointer to overlapped structure for asynchronous operation
  117. );
  118. */
  119. #define MAX_STRING 240
  120. #define LOG_SIZE 2000
  121. #define FIRST_DEBUG_PROC 100
  122. #define OPEN_DEBUGLOG (FIRST_DEBUG_PROC)
  123. #define WRITE_DEBUGLOG (FIRST_DEBUG_PROC+1)
  124. #define WRITE_STATS (FIRST_DEBUG_PROC+2)
  125. HANDLE hDPLAY_VxD=0;
  126. HANDLE hLogMutex=0;
  127. HANDLE hLogFile=0;
  128. PSHARED_LOG_FILE pLogFile=0;
  129. typedef struct _LOGENTRY {
  130. CHAR debuglevel;
  131. CHAR str[1];
  132. } LOGENTRY, *PLOGENTRY;
  133. typedef struct {
  134. UINT nLogEntries;
  135. UINT nCharsPerLine;
  136. } IN_LOGINIT, *PIN_LOGINIT;
  137. typedef struct {
  138. UINT hr;
  139. } OUT_LOGINIT, *POUT_LOGINIT;
  140. typedef struct {
  141. CHAR debuglevel;
  142. CHAR str[1];
  143. } IN_LOGWRITE, *PIN_LOGWRITE;
  144. typedef struct {
  145. UINT hr;
  146. } OUT_LOGWRITE, *POUT_LOGWRITE;
  147. void DbgWriteStats(PIN_WRITESTATS pIn)
  148. {
  149. UINT rc;
  150. UINT cbRet;
  151. if(hDPLAY_VxD){
  152. DeviceIoControl(hDPLAY_VxD,WRITE_STATS,pIn,sizeof(IN_WRITESTATS), &rc, sizeof(rc), &cbRet, NULL);
  153. }
  154. }
  155. static BOOL InitMemLogString(VOID)
  156. {
  157. DWORD dwLastError;
  158. hLogFile=CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, DPLOG_SIZE, BASE_LOG_FILENAME);
  159. dwLastError=GetLastError();
  160. hLogMutex=CreateMutexA(NULL,FALSE,BASE_LOG_MUTEXNAME);
  161. pLogFile=(PSHARED_LOG_FILE)MapViewOfFile(hLogFile, FILE_MAP_ALL_ACCESS,0,0,0);
  162. if(!hLogFile || !hLogMutex || !pLogFile){
  163. if(hLogFile){
  164. CloseHandle(hLogFile);
  165. hLogFile=0;
  166. }
  167. if(hLogMutex){
  168. CloseHandle(hLogMutex);
  169. hLogMutex=0;
  170. }
  171. if(pLogFile){
  172. UnmapViewOfFile(pLogFile);
  173. pLogFile=NULL;
  174. }
  175. return FALSE;
  176. } else {
  177. WaitForSingleObject(hLogMutex,INFINITE);
  178. if((dwLastError!=ERROR_ALREADY_EXISTS) ||
  179. (pLogFile->nEntries > DPLOG_NUMENTRIES) || (pLogFile->nEntries == 0) ||
  180. (pLogFile->cbLine > DPLOG_ENTRYSIZE) || (pLogFile->cbLine == 0) ||
  181. (pLogFile->iWrite > DPLOG_NUMENTRIES) ||
  182. (pLogFile->cInUse > DPLOG_NUMENTRIES)
  183. ){
  184. pLogFile->nEntries = DPLOG_NUMENTRIES;
  185. pLogFile->cbLine = DPLOG_ENTRYSIZE;
  186. pLogFile->iWrite = 0;
  187. pLogFile->cInUse = 0;
  188. }
  189. ReleaseMutex(hLogMutex);
  190. }
  191. return TRUE;
  192. }
  193. static void MemLogString(LPSTR str)
  194. {
  195. PLOG_ENTRY pEntry;
  196. DWORD cbCopy;
  197. if(!hLogFile){
  198. if(!InitMemLogString()){
  199. return;
  200. }
  201. }
  202. WaitForSingleObject(hLogMutex,INFINITE);
  203. pEntry=(PLOG_ENTRY)(((PUCHAR)(pLogFile+1))+(pLogFile->iWrite*(sizeof(LOG_ENTRY)+DPLOG_ENTRYSIZE)));
  204. pEntry->hThread=GetCurrentThreadId();
  205. pEntry->tLogged=timeGetTime();
  206. pEntry->DebugLevel=0;
  207. cbCopy=strlen(str)+1;
  208. if(cbCopy > DPLOG_ENTRYSIZE){
  209. str[DPLOG_ENTRYSIZE]=0;
  210. cbCopy=DPLOG_ENTRYSIZE;
  211. }
  212. memcpy(pEntry->str, str, cbCopy);
  213. if(pLogFile->iWrite+1 > pLogFile->cInUse){
  214. pLogFile->cInUse=pLogFile->iWrite+1;
  215. }
  216. pLogFile->iWrite = (pLogFile->iWrite+1) % pLogFile->nEntries;
  217. ReleaseMutex(hLogMutex);
  218. }
  219. static void LogString( LPSTR str )
  220. {
  221. char logstring[MAX_STRING+sizeof(LOGENTRY)];
  222. int i=0;
  223. PLOGENTRY pLogEntry=(PLOGENTRY)&logstring;
  224. UINT rc;
  225. UINT cbRet;
  226. int maxlen = MAX_STRING+sizeof(LOGENTRY);
  227. if(hDPLAY_VxD && str){
  228. while(str[i] && i < maxlen)
  229. i++;
  230. pLogEntry->debuglevel=0;
  231. memcpy(pLogEntry->str,str,i+1);
  232. DeviceIoControl(hDPLAY_VxD,WRITE_DEBUGLOG,pLogEntry,i+sizeof(LOGENTRY), &rc, sizeof(rc), &cbRet, NULL);
  233. }
  234. if(bLogging & 2){
  235. MemLogString(str);
  236. }
  237. }
  238. static void dumpStr( LPSTR str )
  239. {
  240. /*
  241. * Have to warm the string, since OutputDebugString is buried
  242. * deep enough that it won't page the string in before reading it.
  243. */
  244. int i=0;
  245. if (str)
  246. while(str[i])
  247. i++;
  248. if(!bLogging || bLogging & 1)
  249. {
  250. OUTPUTDEBUGSTRING( str );
  251. OUTPUTDEBUGSTRING("\n");
  252. }
  253. if(bLogging)
  254. {
  255. LogString(str);
  256. }
  257. }
  258. void DebugPrintfInit(void)
  259. {
  260. signed int lDebugLevel;
  261. int i;
  262. char cTopics[100];
  263. #ifndef PROF_SECT
  264. #define PROF_SECT "DirectDraw"
  265. #endif
  266. bDetailOn=1;
  267. for (i=0;i<LAST_TOPIC;i++)
  268. DebugTopics[i].bOn=FALSE;
  269. //ZeroMemory(ProcStats,sizeof(ProcStats));
  270. GETPROFILESTRING( "DirectX", DPF_CONTROL_LINE, "DefaultTopics", cTopics, sizeof(cTopics) );
  271. if (!strcmp(cTopics,"DefaultTopics"))
  272. {
  273. DebugSetTopicsAndLevels("");
  274. bAllowMisc=TRUE;
  275. bPrintAllTopics=TRUE;
  276. lDebugLevel = (signed int) GETPROFILEINT( PROF_SECT, "debug", 0 );
  277. bLogging = (signed int) GETPROFILEINT( PROF_SECT, "log" , 0);
  278. if (lDebugLevel <0)
  279. {
  280. if (lDebugLevel < -9)
  281. lDebugLevel=-9;
  282. bDetailOn |= (1<<(-lDebugLevel));
  283. }
  284. else
  285. {
  286. for (i=0;i<= (lDebugLevel<10?lDebugLevel:10);i++)
  287. bDetailOn |= 1<<i;
  288. }
  289. if(bLogging){
  290. hDPLAY_VxD = CreateFileA("\\\\.\\DPLAY",0,0,0,0,0,0);
  291. if(hDPLAY_VxD != INVALID_HANDLE_VALUE){
  292. IN_LOGINIT In;
  293. OUT_LOGINIT Out;
  294. UINT cbRet;
  295. In.nCharsPerLine=MAX_STRING;
  296. In.nLogEntries=5000;
  297. DeviceIoControl(hDPLAY_VxD,OPEN_DEBUGLOG,&In,sizeof(In), &Out, sizeof(Out), &cbRet, NULL);
  298. }
  299. }
  300. }
  301. else
  302. {
  303. DebugSetTopicsAndLevels(cTopics);
  304. if (!strcmp(cTopics,"?") && !bInited)
  305. {
  306. dumpStr("--------------" DPF_MODULE_NAME " Debug Output Control -------------");
  307. dumpStr("Each character on the control line controls a topic, a detail");
  308. dumpStr("level or an extra info. E.g. 0-36A@ means print detail levels 0");
  309. dumpStr("through 3 and 6 for topic A with source file name and line numbers.");
  310. dumpStr("The extra info control characters are:");
  311. dumpStr(" !: Break on asserts");
  312. dumpStr(" ^: Print TID of calling thread");
  313. dumpStr(" #: Print PID of calling process");
  314. dumpStr(" >: Indent on message detail levels");
  315. dumpStr(" &: Print the topic and detail level of each message");
  316. dumpStr(" =: Print function name");
  317. dumpStr(" +: Print all topics, including topic-less");
  318. dumpStr(" / or -: do not allow topic-less messages");
  319. dumpStr(" @ or $: Print source filename and line number of DPF");
  320. dumpStr("Topics for this module are:");
  321. for(i=0;strcmp(DebugTopics[i].cName,"End");i++)
  322. {
  323. OUTPUTDEBUGSTRING(" ");
  324. OUTPUTDEBUGSTRING(DebugTopics[i].cFlag);
  325. OUTPUTDEBUGSTRING(": ");
  326. dumpStr(DebugTopics[i].cName);
  327. }
  328. dumpStr("Tip: Use 0-3A to get debug info about API calls");
  329. }
  330. }
  331. bInited=TRUE;
  332. }
  333. /*
  334. *
  335. * The full output can be:
  336. * Module:(Executable,TxNNNN,PxNN):FunctionName:"file.c",#nnn(AAnn) Messagemessagemessage
  337. * or, if indentation turned on:
  338. * Module:(Executable,TxNNNN,PxNN):FunctionName:"file.c",#nnn(AAnn) Messagemessagemessage
  339. */
  340. int DebugPrintf(volatile DWORD dwDetail, ...)
  341. {
  342. #define MSGBUFFERSIZE 1000
  343. char cMsg[MSGBUFFERSIZE];
  344. char cTopics[20];
  345. DWORD arg;
  346. LPSTR szFormat;
  347. BOOL bAllowed=FALSE;
  348. BOOL bMiscMessage=TRUE;
  349. int i;
  350. va_list ap;
  351. if (!bInited)
  352. DebugPrintfInit();
  353. //error checking:
  354. if (dwDetail >= 10)
  355. return 1;
  356. if ( (bDetailOn & (1<<dwDetail)) == 0 )
  357. return 1;
  358. if (bMute)
  359. return 1;
  360. va_start(ap,dwDetail);
  361. WSPRINTF(cTopics,"%d",dwDetail);
  362. while ( (arg = va_arg(ap,DWORD)) <256 )
  363. {
  364. if (arg>0 && arg < LAST_TOPIC)
  365. {
  366. bMiscMessage=FALSE;
  367. if (DebugTopics[arg].bOn)
  368. bAllowed = TRUE;
  369. }
  370. }
  371. if (bMiscMessage)
  372. if (bAllowMisc || dwDetail == 0)
  373. bAllowed=TRUE;
  374. if ( bPrintAllTopics )
  375. bAllowed=TRUE;
  376. if (!bAllowed)
  377. return FALSE;
  378. szFormat = (LPSTR) UlongToPtr(arg);
  379. cMsg[0]=0;
  380. /*
  381. * Add the module name first
  382. */
  383. if (bPrintModuleName)
  384. {
  385. WSPRINTF( cMsg+strlen(cMsg),DPF_MODULE_NAME ":" );
  386. }
  387. if (bPrintExecutableName || bPrintTID || bPrintPID)
  388. WSPRINTF( cMsg+strlen(cMsg),"(");
  389. #ifdef WIN32
  390. #if 0
  391. /*
  392. * deleted due to RIP in GetModuleFilename on debug windows when win16 lock held
  393. */
  394. if (bPrintExecutableName)
  395. {
  396. GetModuleFileName(NULL,str,256);
  397. if (mystrrchr(str,'\\'))
  398. WSPRINTF(cMsg+strlen(cMsg),"%12s",mystrrchr(str,'\\')+1);
  399. }
  400. #endif
  401. if (bPrintPID)
  402. {
  403. if (bPrintExecutableName)
  404. strcat(cMsg,",");
  405. WSPRINTF( cMsg+strlen(cMsg),"Px%02x",GetCurrentProcessId());
  406. }
  407. if (bPrintTID)
  408. {
  409. if (bPrintExecutableName || bPrintPID)
  410. strcat(cMsg,",");
  411. WSPRINTF( cMsg+strlen(cMsg),"Tx%04x",GetCurrentThreadId());
  412. }
  413. if (bPrintExecutableName || bPrintTID || bPrintPID)
  414. WSPRINTF( cMsg+strlen(cMsg),"):");
  415. #endif
  416. if (bPrintFunctionName)
  417. {
  418. WSPRINTF( cMsg+strlen(cMsg),cFnName);
  419. }
  420. if (bPrintFileNames || bPrintLineNumbers)
  421. {
  422. if (mystrrchr(cFile,'\\'))
  423. WSPRINTF( cMsg+strlen(cMsg),":%12s",mystrrchr(cFile,'\\')+1 );
  424. else
  425. WSPRINTF( cMsg+strlen(cMsg),":%12s",cFile);
  426. WSPRINTF( cMsg+strlen(cMsg),"@%d",dwLineNo);
  427. }
  428. if (bPrintTopicsAndLevels)
  429. {
  430. WSPRINTF( cMsg+strlen(cMsg),"(%3s)",cTopics);
  431. }
  432. if (cMsg[strlen(cMsg)-1] != ':')
  433. WSPRINTF( cMsg+strlen(cMsg),":");
  434. if (bIndentOnMessageLevel)
  435. {
  436. for(i=0;(DWORD)i<dwDetail;i++)
  437. strcat(cMsg," ");
  438. }
  439. WVSPRINTF( cMsg+LSTRLEN( cMsg ), szFormat, ap);
  440. if (bAllowed)
  441. dumpStr( cMsg );
  442. va_end(ap);
  443. return 1;
  444. }
  445. void DebugSetMute(BOOL bMuteFlag)
  446. {
  447. bMute=bMuteFlag;
  448. }
  449. void DebugEnterAPI(char *pFunctionName , LPDWORD pIface)
  450. {
  451. DebugPrintf(2,A,"%08x->%s",pIface,pFunctionName);
  452. }
  453. void DebugSetTopicsAndLevels(char * cTopics)
  454. {
  455. int i;
  456. int j;
  457. bAllowMisc=TRUE;
  458. bBreakOnAsserts=FALSE;
  459. bPrintLineNumbers=FALSE;
  460. bPrintFileNames=FALSE;
  461. bPrintExecutableName=FALSE;
  462. bPrintTID=FALSE;
  463. bPrintPID=FALSE;
  464. bIndentOnMessageLevel=FALSE;
  465. bPrintTopicsAndLevels=FALSE;
  466. bPrintFunctionName=FALSE;
  467. bPrintAPIStats=FALSE;
  468. bPrintAllTopics=FALSE;
  469. bDetailOn=1; /* always print detail level 0*/
  470. for (i=0;(DWORD)i<strlen(cTopics);i++)
  471. {
  472. switch (cTopics[i])
  473. {
  474. case '/':
  475. case '-':
  476. bAllowMisc=FALSE;
  477. break;
  478. case '!':
  479. bBreakOnAsserts=TRUE;
  480. break;
  481. case '@':
  482. bPrintLineNumbers=TRUE;
  483. break;
  484. case '$':
  485. bPrintFileNames=TRUE;
  486. break;
  487. #if 0
  488. /*
  489. * Currently deleted because GetModuleFilename causes a RIP on debug windows when the win16
  490. * lock is held.
  491. */
  492. case '?':
  493. bPrintExecutableName=TRUE;
  494. break;
  495. #endif
  496. case '^':
  497. bPrintTID=TRUE;
  498. break;
  499. case '#':
  500. bPrintPID=TRUE;
  501. break;
  502. case '>':
  503. bIndentOnMessageLevel=TRUE;
  504. break;
  505. case '&':
  506. bPrintTopicsAndLevels=TRUE;
  507. break;
  508. case '=':
  509. bPrintFunctionName=TRUE;
  510. break;
  511. case '%':
  512. bPrintAPIStats=TRUE;
  513. break;
  514. case '+':
  515. bPrintAllTopics=TRUE;
  516. break;
  517. default:
  518. if (cTopics[i]>='0' && cTopics[i]<='9')
  519. {
  520. if (cTopics[i+1]=='-')
  521. {
  522. if (cTopics[i+2]>='0' && cTopics[i+2]<='9')
  523. {
  524. for(j=cTopics[i]-'0';j<=cTopics[i+2]-'0';j++)
  525. bDetailOn |= 1<<j;
  526. i+=2;
  527. }
  528. }
  529. else
  530. bDetailOn |= 1<<(cTopics[i]-'0');
  531. }
  532. else
  533. {
  534. for(j=0;j<LAST_TOPIC;j++)
  535. if (cTopics[i]==DebugTopics[j].cFlag[0])
  536. DebugTopics[j].bOn=TRUE;
  537. }
  538. } //end switch
  539. }
  540. }
  541. /*
  542. * NOTE: I don't want to get into error checking for buffer overflows when
  543. * trying to issue an assertion failure message. So instead I just allocate
  544. * a buffer that is "bug enough" (I know, I know...)
  545. */
  546. #define ASSERT_BUFFER_SIZE 512
  547. #define ASSERT_BANNER_STRING "************************************************************"
  548. #define ASSERT_BREAK_SECTION "BreakOnAssert"
  549. #define ASSERT_BREAK_DEFAULT FALSE
  550. #define ASSERT_MESSAGE_LEVEL 0
  551. void _DDAssert( LPCSTR szFile, int nLine, LPCSTR szCondition )
  552. {
  553. char buffer[ASSERT_BUFFER_SIZE];
  554. /*
  555. * Build the debug stream message.
  556. */
  557. WSPRINTF( buffer, "ASSERTION FAILED! File %s Line %d: %s", szFile, nLine, szCondition );
  558. /*
  559. * Actually issue the message. These messages are considered error level
  560. * so they all go out at error level priority.
  561. */
  562. dprintf( ASSERT_MESSAGE_LEVEL, ASSERT_BANNER_STRING );
  563. dprintf( ASSERT_MESSAGE_LEVEL, buffer );
  564. dprintf( ASSERT_MESSAGE_LEVEL, ASSERT_BANNER_STRING );
  565. /*
  566. * Should we drop into the debugger?
  567. */
  568. if( bBreakOnAsserts || GETPROFILEINT( PROF_SECT, ASSERT_BREAK_SECTION, ASSERT_BREAK_DEFAULT ) )
  569. {
  570. /*
  571. * Into the debugger we go...
  572. */
  573. DEBUG_BREAK();
  574. }
  575. }
  576. #ifdef cplusplus
  577. }
  578. #endif
  579. #endif //defined debug