Leaked source code of windows server 2003
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.

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