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.

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