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.
 
 
 
 
 
 

789 lines
20 KiB

/******************************Module*Header*******************************\
* Module Name: debug.c
*
* This file is for debugging tools and extensions.
*
* Created: 24-Jan-1992
* Author: John Colleran
*
* History:
* Feb 17 92 Matt Felton (mattfe) lots of additional exentions for filtering
* Jul 13 92 (v-cjones) Added API & MSG profiling debugger extensions, fixed
* other extensions to handle segment motion correctly,
* & cleaned up the file in general
* Jan 3 96 Neil Sandlin (neilsa) integrated this routine into vdmexts
*
* Copyright (c) 1992 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include <wmdisp32.h>
#include <wcuricon.h>
#include <wucomm.h>
INT cAPIThunks;
//
// WARNING: The following code was copied from WOWTBL.C
//
typedef struct {
WORD kernel;
WORD dkernel;
WORD user;
WORD duser;
WORD gdi;
WORD dgdi;
WORD keyboard;
WORD sound;
WORD shell;
WORD winsock;
WORD toolhelp;
WORD mmedia;
WORD commdlg;
#ifdef FE_IME
WORD winnls;
#endif // FE_IME
#ifdef FE_SB
WORD wifeman;
#endif // FE_SB
} TABLEOFFSETS;
typedef TABLEOFFSETS UNALIGNED *PTABLEOFFSETS;
TABLEOFFSETS tableoffsets;
INT TableOffsetFromName(PSZ szTab);
INT ModFromCallID(INT iFun)
{
PTABLEOFFSETS pto = &tableoffsets;
LPVOID lpAddress;
GETEXPRADDR(lpAddress, "wow32!tableoffsets");
READMEM(lpAddress, &tableoffsets, sizeof(TABLEOFFSETS));
if (iFun < pto->user)
return MOD_KERNEL;
if (iFun < pto->gdi)
return MOD_USER;
if (iFun < pto->keyboard)
return MOD_GDI;
if (iFun < pto->sound)
return MOD_KEYBOARD;
if (iFun < pto->shell)
return MOD_SOUND;
if (iFun < pto->winsock)
return MOD_SHELL;
if (iFun < pto->toolhelp)
return MOD_WINSOCK;
if (iFun < pto->mmedia)
return MOD_TOOLHELP;
if (iFun < pto->commdlg) {
return(MOD_MMEDIA);
}
#if defined(FE_SB)
#if defined(FE_IME)
if (iFun < pto->winnls)
return MOD_COMMDLG;
if (iFun < pto->wifeman)
return MOD_WINNLS;
if (iFun < cAPIThunks)
return MOD_WIFEMAN;
#else
if (iFun < pto->wifeman)
return MOD_COMMDLG;
if (iFun < cAPIThunks)
return MOD_WIFEMAN;
#endif
#elif defined(FE_IME)
if (iFun < pto->winnls)
return MOD_COMMDLG;
if (iFun < cAPIThunks)
return MOD_WINNLS;
#else
if (iFun < cAPIThunks)
return MOD_COMMDLG;
#endif
return -1;
}
PSZ apszModNames[] = { "Kernel",
"User",
"Gdi",
"Keyboard",
"Sound",
"Shell",
"Winsock",
"Toolhelp",
"MMedia",
"Commdlg"
#ifdef FE_IME
,"WinNLS"
#endif
#ifdef FE_SB
,"WifeMan"
#endif
};
INT nModNames = NUMEL(apszModNames);
PSZ GetModName(INT iFun)
{
INT nMod;
nMod = ModFromCallID(iFun);
if (nMod == -1) {
return "BOGUS!!";
}
nMod = nMod >> 12; // get the value into the low byte
return apszModNames[nMod];
}
INT GetOrdinal(INT iFun)
{
INT nMod;
nMod = ModFromCallID(iFun);
if (nMod == -1) {
return 0;
}
return (iFun - TableOffsetFromName(apszModNames[nMod >> 12]));
}
INT TableOffsetFromName(PSZ szTab)
{
INT i;
PTABLEOFFSETS pto = &tableoffsets;
for (i = 0; i < NUMEL(apszModNames); i++) {
if (!strcmp(szTab, apszModNames[i]))
break;
}
if (i >= NUMEL(apszModNames))
return 0;
switch (i << 12) {
case MOD_KERNEL:
return pto->kernel;
case MOD_USER:
return pto->user;
case MOD_DGDI:
return pto->gdi;
case MOD_KEYBOARD:
return pto->keyboard;
case MOD_SOUND:
return pto->sound;
case MOD_SHELL:
return pto->shell;
case MOD_WINSOCK:
return pto->winsock;
case MOD_TOOLHELP:
return pto->toolhelp;
case MOD_MMEDIA:
return pto->mmedia;
case MOD_COMMDLG:
return(pto->commdlg);
#ifdef FE_IME
case MOD_WINNLS:
return pto->winnls;
#endif
#ifdef FE_SB
case MOD_WIFEMAN:
return pto->wifeman;
#endif
default:
return(-1);
}
}
/********* local functions for WOWPROFILE support *********/
/******* function protoypes for local functions for WOWPROFILE support *******/
BOOL WDGetAPIProfArgs(LPSZ lpszArgStr,
INT iThkTblMax,
PPA32 ppaThkTbls,
LPSZ lpszTab,
BOOL *bTblAll,
LPSZ lpszFun,
int *iFunInd);
BOOL WDGetMSGProfArgs(LPSZ lpszArgStr,
LPSZ lpszMsg,
int *iMsgNum);
INT WDParseArgStr(LPSZ lpszArgStr, CHAR **argv, INT iMax);
BOOL WDGetAPIProfArgs(LPSZ lpszArgStr,
INT iThkTblMax,
PPA32 ppaThkTbls,
LPSZ lpszTab,
BOOL *bTblAll,
LPSZ lpszFun,
int *iFunInd) {
/*
* Decomposes & interprets argument string to apiprofdmp extension.
* INPUT:
* lpszArgStr - ptr to input arg string
* iThkTblMax - # tables in the thunk tables
* ppaThkTbls - ptr to the thunk tables
* OUTPUT:
* lpszTab - ptr to table name
* bTblAll - 0 => dump specific table, 1 => dump all tables
* lpszFun - ptr to API name
* iFunInd - -1 => dump specific API name
* 0 => dump all API entires in table
* >0 => dump specific API number (decimal)
* RETURN: 0 => OK, 1 => input error (show Usage)
*
* legal forms: !wow32.apiprofdmp
* !wow32.apiprofdmp user
* !wow32.apiprofdmp user createwindow
* !wow32.apiprofdmp user 41
* !wow32.apiprofdmp createwindow
* !wow32.apiprofdmp 41
*/
INT i, nArgs;
CHAR *argv[2];
nArgs = WDParseArgStr(lpszArgStr, argv, 2);
/* if no arguments dump all entries in all tables */
if( nArgs == 0 ) {
*iFunInd = 0; // specify dump all API entires in the table
*bTblAll = 1; // specify dump all tables
return(0);
}
/* see if 1st arg is a table name */
*bTblAll = 1; // specify dump all tables
for (i = 0; i < nModNames; i++) {
if (!lstrcmpi(apszModNames[i], argv[0])) {
lstrcpy(lpszTab, apszModNames[i]);
*bTblAll = 0; // specify dump specific table
/* if we got a table name match & only one arg, we're done */
if( nArgs == 1 ) {
*iFunInd = 0; // specify dump all API entries in the table
return(0);
}
break;
}
}
#if 0
for(i = 0; i < iThkTblMax; i++) {
CHAR temp[40], *TblEnt[2], szTabName[40];
PA32 awThkTbl;
/* get table name string from thunk tables */
READMEM_XRETV(awThkTbl, &ppaThkTbls[i], 0);
READMEM_XRETV(szTabName, awThkTbl.lpszW32, 0);
/* get rid of trailing spaces from table name string */
lstrcpy(temp, szTabName);
WDParseArgStr(temp, TblEnt, 1);
/* if we found a table name that matches the 1st arg...*/
if( !lstrcmpi(argv[0], TblEnt[0]) ) {
lstrcpy(lpszTab, szTabName);
*bTblAll = 0; // specify dump specific table
/* if we got a table name match & only one arg, we're done */
if( nArgs == 1 ) {
*iFunInd = 0; // specify dump all API entries in the table
return(0);
}
break;
}
}
#endif
/* if 2 args && the 1st doesn't match a table name above => bad input */
if( (nArgs > 1) && (*bTblAll) ) {
return(1);
}
/* set index to API spec */
nArgs--;
/* try to convert API spec to a number */
*iFunInd = atoi(argv[nArgs]);
lstrcpy(lpszFun, argv[nArgs]);
/* if API spec is not a number => it's a name */
if( *iFunInd == 0 ) {
*iFunInd = -1; // specify API search by name
}
/* else if API number is bogus -- complain */
else if( *iFunInd < 0 ) {
return(1);
}
return(0);
}
BOOL WDGetMSGProfArgs(LPSZ lpszArgStr,
LPSZ lpszMsg,
int *iMsgNum) {
/*
* Decomposes & interprets argument string to msgprofdmp extension.
* INPUT:
* lpszArgStr - ptr to input arg string
* OUTPUT:
* lpszMsg - ptr to message name
* iMsgNum - -1 => dump all message entries in the table
* -2 => lpszMsg contains specific MSG name
* >=0 => dump specific message number
* RETURN: 0 => OK, 1 => input error (show Usage)
*/
INT nArgs;
CHAR *argv[2];
nArgs = WDParseArgStr(lpszArgStr, argv, 1);
/* if no arguments dump all entries in all tables */
if( nArgs == 0 ) {
*iMsgNum = -1; // specify dump all MSG entires in the table
return(0);
}
if( !lstrcmpi(argv[0], "HELP") )
return(1);
/* try to convert MSG spec to a number */
*iMsgNum = atoi(argv[0]);
lstrcpy(lpszMsg, argv[0]);
/* if MSG spec is not a number => it's a name */
if( *iMsgNum == 0 ) {
*iMsgNum = -2; // specify lpszMsg contains name to search for
}
/* else if MSG number is bogus -- complain */
else if( *iMsgNum < 0 ) {
return(1);
}
return(0);
}
/******* API profiler table functions ********/
/* init some common strings */
CHAR szAPI[] = "API# API Name";
CHAR szMSG[] = "MSG # MSG Name";
CHAR szTITLES[] = "# Calls Tot. tics tics/call";
CHAR szDASHES[] = "----------------------------------- ------- --------------- ---------------";
CHAR szTOOBIG[] = "too large for table.";
CHAR szNOTUSED[] = "Unused table index.";
CHAR szRNDTRIP[] = "Round trip message profiling";
CHAR szCLEAR[] = "Remember to clear the message profile tables.";
VOID
apiprofclr(
CMD_ARGLIST
)
{
int iTab, iFun, iEntries;
INT iThkTblMax;
W32 awAPIEntry;
PW32 pawAPIEntryTbl;
PA32 awThkTbl;
PPA32 ppaThkTbls;
CHAR szTable[20];
CMD_INIT();
ASSERT_CHECKED_WOW_PRESENT;
GETEXPRVALUE(iThkTblMax, "wow32!iThunkTableMax", INT);
GETEXPRVALUE(ppaThkTbls, "wow32!pawThunkTables", PPA32);
PRINTF("Clearing:");
for(iTab = 0; iTab < iThkTblMax; iTab++) {
READMEM_XRET(awThkTbl, &ppaThkTbls[iTab]);
READMEM_XRET(szTable, awThkTbl.lpszW32);
PRINTF(" %s", szTable);
pawAPIEntryTbl = awThkTbl.lpfnA32;
READMEM_XRET(iEntries, awThkTbl.lpiFunMax);
for(iFun = 0; iFun < iEntries; iFun++) {
READMEM_XRET(awAPIEntry, &pawAPIEntryTbl[iFun]);
awAPIEntry.cCalls = 0L;
awAPIEntry.cTics = 0L;
WRITEMEM_XRET(&pawAPIEntryTbl[iFun], awAPIEntry);
}
}
PRINTF("\n");
return;
}
VOID
apiprofdmp(
CMD_ARGLIST
)
{
BOOL bTblAll, bFound;
int i, iFun, iFunInd;
INT iThkTblMax;
W32 awAPIEntry;
PW32 pawAPIEntryTbl;
PA32 awThkTbl;
PPA32 ppaThkTbls;
CHAR szTab[20], szFun[40], szTable[20], szFunName[40];
CMD_INIT();
ASSERT_CHECKED_WOW_PRESENT;
GETEXPRVALUE(iThkTblMax, "wow32!iThunkTableMax", INT);
GETEXPRVALUE(ppaThkTbls, "wow32!pawThunkTables", PPA32);
GETEXPRVALUE(cAPIThunks, "wow32!cAPIThunks", INT);
GETEXPRVALUE(i, "wow32!nModNames", INT);
if (i != nModNames) {
PRINTF("Error: mismatch of nModNames in apiprofdmp.\nExtension is out of date\n");
return;
}
if( WDGetAPIProfArgs(lpArgumentString,
iThkTblMax,
ppaThkTbls,
szTab,
&bTblAll,
szFun,
&iFunInd) ) {
helpAPIProfDmp();
return;
}
bFound = FALSE;
#if 0
for(iTab = 0; iTab < iThkTblMax; iTab++) {
READMEM_XRET(awThkTbl, &ppaThkTbls[iTab]);
READMEM_XRET(szTable, awThkTbl.lpszW32);
/* if dump all tables || dump this specific table */
if( bTblAll || !lstrcmp(szTab, szTable) ) {
pawAPIEntryTbl = awThkTbl.lpfnA32;
#endif
for (i = 0; i < nModNames; i++) {
READMEM_XRET(awThkTbl, &ppaThkTbls[0]);
lstrcpy(szTable, apszModNames[i]);
/* if dump all tables || dump this specific table */
if (bTblAll || !lstrcmpi(szTab, apszModNames[i])) {
INT nFirst, nLast;
nFirst = TableOffsetFromName(apszModNames[i]);
if (i < nModNames - 1)
nLast = TableOffsetFromName(apszModNames[i+1]) - 1;
else
nLast = cAPIThunks - 1;
pawAPIEntryTbl = awThkTbl.lpfnA32;
/* if dump a specific API number */
if( iFunInd > 0 ) {
PRINTF("\n>>>> %s\n", szTable);
PRINTF("%s %s\n%s\n", szAPI, szTITLES, szDASHES);
//if( iFunInd >= *(awThkTbl.lpiFunMax) ) {
if( iFunInd > nLast - nFirst ) {
PRINTF("Index #%d %s.\n", GetOrdinal(iFunInd), szTOOBIG);
}
else {
bFound = TRUE;
// READMEM_XRET(awAPIEntry, &pawAPIEntryTbl[iFunInd]);
READMEM_XRET(awAPIEntry, &pawAPIEntryTbl[nFirst + iFunInd]);
READMEM_XRET(szFunName, awAPIEntry.lpszW32);
if( szFunName[0] ) {
PRINTF("%4d %30s ", GetOrdinal(iFunInd), szFunName);
}
else {
PRINTF("%4d %30s ", GetOrdinal(iFunInd), szNOTUSED);
}
PRINTF("%7ld %15ld ", awAPIEntry.cCalls, awAPIEntry.cTics);
if(awAPIEntry.cCalls) {
PRINTF("%15ld\n", awAPIEntry.cTics/awAPIEntry.cCalls);
} else {
PRINTF("%15ld\n", 0L);
}
}
}
/* else if dump an API by name */
else if ( iFunInd == -1 ) {
// READMEM_XRET(iEntries, awThkTbl.lpiFunMax);
// for(iFun = 0; iFun < iEntries; iFun++) {
for(iFun = nFirst; iFun <= nLast; iFun++) {
READMEM_XRET(awAPIEntry, &pawAPIEntryTbl[iFun]);
READMEM_XRET(szFunName, awAPIEntry.lpszW32);
if ( !lstrcmpi(szFun, szFunName) ) {
PRINTF("\n>>>> %s\n", szTable);
PRINTF("%s %s\n%s\n", szAPI, szTITLES, szDASHES);
PRINTF("%4d %30s %7ld %15ld ",
GetOrdinal(iFun),
szFunName,
awAPIEntry.cCalls,
awAPIEntry.cTics);
if(awAPIEntry.cCalls) {
PRINTF("%15ld\n", awAPIEntry.cTics/awAPIEntry.cCalls);
} else {
PRINTF("%15ld\n", 0L);
}
return;
}
}
}
/* else dump all the API's in the table */
else {
PRINTF("\n>>>> %s\n", szTable);
PRINTF("%s %s\n%s\n", szAPI, szTITLES, szDASHES);
bFound = TRUE;
// READMEM_XRET(iEntries, awThkTbl.lpiFunMax);
// for(iFun = 0; iFun < iEntries; iFun++) {
for(iFun = nFirst; iFun <= nLast; iFun++) {
READMEM_XRET(awAPIEntry, &pawAPIEntryTbl[iFun]);
READMEM_XRET(szFunName, awAPIEntry.lpszW32);
if(awAPIEntry.cCalls) {
PRINTF("%4d %30s %7ld %15ld %15ld\n",
GetOrdinal(iFun),
szFunName,
awAPIEntry.cCalls,
awAPIEntry.cTics,
awAPIEntry.cTics/awAPIEntry.cCalls);
}
}
if( !bTblAll ) {
return;
}
}
}
}
if( !bFound ) {
PRINTF("\nCould not find ");
if( !bTblAll ) {
PRINTF("%s ", szTab);
}
PRINTF("API: %s\n", szFun);
helpAPIProfDmp();
}
return;
}
/******* MSG profiler table functions ********/
VOID
msgprofclr(
CMD_ARGLIST
)
{
int iMsg;
INT iMsgMax;
M32 awM32;
PM32 paw32Msg;
CMD_INIT();
ASSERT_CHECKED_WOW_PRESENT;
GETEXPRVALUE(iMsgMax, "wow32!iMsgMax", INT);
GETEXPRVALUE(paw32Msg, "wow32!paw32Msg", PM32);
PRINTF("Clearing Message profile table");
for(iMsg = 0; iMsg < iMsgMax; iMsg++) {
READMEM_XRET(awM32, &paw32Msg[iMsg]);
awM32.cCalls = 0L;
awM32.cTics = 0L;
WRITEMEM_XRET(&paw32Msg[iMsg], awM32);
}
PRINTF("\n");
return;
}
VOID
msgprofdmp(
CMD_ARGLIST
)
{
int iMsg, iMsgNum;
INT iMsgMax;
BOOL bFound;
M32 aw32Msg;
PM32 paw32Msg;
CHAR szMsg[40], *argv[2], szMsg32[40], szMsgName[40];
CMD_INIT();
ASSERT_CHECKED_WOW_PRESENT;
GETEXPRVALUE(iMsgMax, "wow32!iMsgMax", INT);
GETEXPRVALUE(paw32Msg, "wow32!paw32Msg", PM32);
if( WDGetMSGProfArgs(lpArgumentString, szMsg, &iMsgNum) ) {
helpMsgProfDmp();
return;
}
PRINTF("%s %s\n%s\n", szMSG, szTITLES, szDASHES);
if( iMsgNum > iMsgMax ) {
PRINTF("MSG #%4d %s.\n", iMsgNum, szTOOBIG);
return;
}
bFound = 0;
for(iMsg = 0; iMsg < iMsgMax; iMsg++) {
READMEM_XRET(aw32Msg, &paw32Msg[iMsg]);
READMEM_XRET(szMsgName, aw32Msg.lpszW32);
/* if specific msg name, parse name from "WM_MSGNAME 0x00XX" format */
if( iMsgNum == -2 ) {
lstrcpy(szMsg32, szMsgName);
WDParseArgStr(szMsg32, argv, 1);
}
/* if 'all' msgs || specific msg # || specific msg name */
if( (iMsgNum == -1) || (iMsg == iMsgNum) ||
( (iMsgNum == -2) && (!lstrcmp(szMsg, argv[0])) ) ) {
bFound = 1;
if(aw32Msg.cCalls) {
PRINTF("0x%-4X %28s %7ld %15ld %15ld\n",
iMsg,
szMsgName,
aw32Msg.cCalls,
aw32Msg.cTics,
aw32Msg.cTics/aw32Msg.cCalls);
}
/* else if MSG wasn't sent & we're not dumping the whole table */
else if( iMsgNum != -1 ) {
PRINTF("0x%-4X %28s %7ld %15ld %15ld\n",
iMsgNum,
szMsgName,
0L,
0L,
0L);
}
/* if we're not dumping the whole table, we're done */
if( iMsgNum != -1 ) {
return;
}
}
}
if( !bFound ) {
PRINTF("\nCould not find MSG: %s\n", szMsg);
helpMsgProfDmp();
}
return;
}
void
msgprofrt(
CMD_ARGLIST
)
{
INT fWMsgProfRT;
LPVOID lpAddress;
CMD_INIT();
ASSERT_CHECKED_WOW_PRESENT;
GETEXPRADDR(lpAddress, "wow32!fWMsgProfRT");
READMEM_XRET(fWMsgProfRT, lpAddress);
fWMsgProfRT = 1 - fWMsgProfRT;
WRITEMEM_XRET(lpAddress, fWMsgProfRT);
if( fWMsgProfRT ) {
PRINTF("\n%s ENABLED.\n%s\n\n", szRNDTRIP, szCLEAR);
}
else {
PRINTF("\n%s DISABLED.\n%s\n\n", szRNDTRIP, szCLEAR);
}
return;
}