/*++ Copyright (c) 1990 Microsoft Corporation Module Name: wdbgxlib.c Abstract: This module realizes most of the routines needed for the rdbss/smbmini debugger extension. Author: Balan Sethu Raman (SethuR) 11-May-1994 Notes: Revision History: 11-Nov-1994 SethuR Created 11-Nov-1995 Changed to newer windbg apis --*/ #define KDEXT_32BIT #include "rxovride.h" //common compile flags #include #include #include "ntverp.h" #include #include #include #include #include #include #include #include #include extern "C" { #include } #include "dbg.h" #include "topobj.h" #include "smartptr.h" #include "trc.h" WINDBG_EXTENSION_APIS ExtensionApis; EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 }; BOOL ParseTrc(PCSTR args, DWORD *dwLines); #define ERRPRT dprintf #define NL 1 #define NONL 0 USHORT SavedMajorVersion; USHORT SavedMinorVersion; BOOL ChkTarget; // is debuggee a CHK build? /* * Print out an optional message, an ANSI_STRING, and maybe a new-line */ BOOL wPrintStringA( IN LPSTR msg OPTIONAL, IN PANSI_STRING pStr, IN BOOL nl ) { PCHAR StringData; ULONG BytesRead; if( msg ) dprintf( msg ); if( pStr->Length == 0 ) { if( nl ) dprintf( "\n" ); return TRUE; } StringData = (PCHAR)LocalAlloc( LPTR, pStr->Length + 1 ); if( StringData == NULL ) { ERRPRT( "Out of memory!\n" ); return FALSE; } ReadMemory( (ULONG_PTR)pStr->Buffer, StringData, pStr->Length, &BytesRead ); if ( BytesRead ) { StringData[ pStr->Length ] = '\0'; dprintf("%s%s", StringData, nl ? "\n" : "" ); } LocalFree((HLOCAL)StringData); return BytesRead; } /* * Fetches the data at the given address */ BOOLEAN wGetData( ULONG_PTR dwAddress, PVOID ptr, ULONG size, IN PSZ type) { BOOL b; ULONG BytesRead; b = ReadMemory( dwAddress, ptr, size, &BytesRead ); if (!b || BytesRead != size ) { dprintf( "Unable to read %u bytes at %X, for %s\n", size, dwAddress, type ); return FALSE; } return TRUE; } /* * Fetch the null terminated ASCII string at dwAddress into buf */ BOOL wGetString( ULONG_PTR dwAddress, PSZ buf ) { for(;;) { if( !wGetData( dwAddress,buf, 1, "..stringfetch") ){ //dprintf("readfailure at %08lx\n",dwAddress); return FALSE; } //dprintf ("stringing %08lx %08lx %c\n", dwAddress, buf, // ((*buf==0)?'.':*buf) ); if ( *buf == '\0' ) { break; } dwAddress++; buf++; }; return TRUE; } #if 0 /* * Get 'size' bytes from the debuggee program at 'dwAddress' and place it * in our address space at 'ptr'. Use 'type' in an error printout if necessary */ BOOL wGetData_srv( IN LPVOID ptr, IN ULONG_PTR dwAddress, IN ULONG size, IN PCSTR type ) { BOOL b; ULONG BytesRead; ULONG count; while( size > 0 ) { count = min( size, 3000 ); b = ReadMemory((ULONG) dwAddress, ptr, count, &BytesRead ); if (!b || BytesRead != count ) { ERRPRT( "Unable to read %u bytes at %X, for %s\n", size, dwAddress, type ); return FALSE; } dwAddress += count; size -= count; ptr = (LPVOID)((ULONG)ptr + count); } return TRUE; } /* * Follow a LIST_ENTRY list beginning with a head at dwListHeadAddr in the debugee's * address space. For each element in the list, print out the pointer value at 'offset' */ BOOL PrintListEntryList( IN ULONG_PTR dwListHeadAddr, IN LONG offset ) { LIST_ENTRY ListEntry; ULONG i=0; BOOL retval = TRUE; ULONG count = 20; if( !wGetData_srv( &ListEntry, dwListHeadAddr, sizeof( ListEntry ), "LIST_ENTRY" ) ) return FALSE; while( count-- ) { if( (ULONG_PTR)ListEntry.Flink == dwListHeadAddr || (ULONG_PTR)ListEntry.Flink == 0 ) break; if( !wGetData_srv( &ListEntry, (ULONG_PTR)ListEntry.Flink, sizeof( ListEntry ), "ListEntry" ) ) { retval = FALSE; break; } dprintf( "%16X%s", (LONG)ListEntry.Flink + offset, (i && !(i&3)) ? "\n" : "" ); i++; } if( count == 0 && (ULONG_PTR)ListEntry.Flink != dwListHeadAddr && ListEntry.Flink ) { dprintf( "\nTruncated list dump\n" ); } else if( ! ( i && !(i&3) ) ) { dprintf( "\n" ); } return retval; } #endif /* * Print out a single HEX character */ VOID wPrintHexChar( IN UCHAR c ) { dprintf( "%c%c", "0123456789abcdef"[ (c>>4)&0xf ], "0123456789abcdef"[ c&0xf ] ); } /* * Print out 'buf' of 'cbuf' bytes as HEX characters */ VOID wPrintHexBuf( IN PUCHAR buf, IN ULONG cbuf ) { while( cbuf-- ) { wPrintHexChar( *buf++ ); dprintf( " " ); } } #if 0 /* * Fetch the null terminated UNICODE string at dwAddress into buf */ BOOL GetString( IN ULONG_PTR dwAddress, IN LPWSTR buf, IN ULONG MaxChars ) { do { if( !wGetData_srv( buf, dwAddress, sizeof( *buf ), "UNICODE Character" ) ) return FALSE; dwAddress += sizeof( *buf ); } while( --MaxChars && *buf++ != '\0' ); return TRUE; } #endif VOID WinDbgExtensionDllInit( PWINDBG_EXTENSION_APIS lpExtensionApis, USHORT MajorVersion, USHORT MinorVersion ) { // ExtensionApis = *lpExtensionApis; memcpy(&ExtensionApis, lpExtensionApis, sizeof(ExtensionApis)); SavedMajorVersion = MajorVersion; SavedMinorVersion = MinorVersion; ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE; } DECLARE_API( version ) { #if DBG PCSTR kind = "Checked"; #else PCSTR kind = "Free"; #endif dprintf( "%s RDBSS+RdpDr Extension dll for Build %d debugging %s kernel for Build %d\n", kind, VER_PRODUCTBUILD, SavedMajorVersion == 0x0c ? "Checked" : "Free", SavedMinorVersion ); } VOID CheckVersion( VOID ) { #if DBG if ((SavedMajorVersion != 0x0c) || (SavedMinorVersion != VER_PRODUCTBUILD)) { dprintf("\r\n*** Extension DLL(%d Checked) does not match target system(%d %s)\r\n\r\n", VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" ); } #else if ((SavedMajorVersion != 0x0f) || (SavedMinorVersion != VER_PRODUCTBUILD)) { dprintf("\r\n*** Extension DLL(%d Free) does not match target system(%d %s)\r\n\r\n", VER_PRODUCTBUILD, SavedMinorVersion, (SavedMajorVersion==0x0f) ? "Free" : "Checked" ); } #endif } LPEXT_API_VERSION ExtensionApiVersion( VOID ) { return &ApiVersion; } LPSTR LibCommands[] = { "dump @
", "listref [address of specific RefCount object]" "ddd
-- dump using context" "columns -- controls the number of columns in the display ", "lg [][@filename] -- dump the log", "gv -- dump out important variables", "activerx [fcbtomatch]-- dump the list of active contexts", "flags -- print which flags are actually set (no text yet)", "cxr -- looks up cxr value from memory and does !cxr/!kb", "irp,thread,fcb,fobx,srvopen,exchange,stuff,smbbuf -- dumps the named item from the last dumpee", "version", 0 }; DECLARE_API( help ) { int i; dprintf( "\nRDBSS debugger extensions:\n"); for( i=0; LibCommands[i]; i++ ) dprintf( " %s\n", LibCommands[i] ); } ULONG FieldOffsetOfContextListEntryInRxC(); VOID ReadRxContextFields(ULONG_PTR RxContext,PULONG_PTR pFcb,PULONG_PTR pThread, PULONG_PTR pMiniCtx2); DECLARE_API( dump ); DECLARE_API( activerx ) { //ULONG dwAddress; LIST_ENTRY LEbuffer; PLIST_ENTRY pRxActiveContexts,pListEntry; ULONG_PTR RxContext,CapturedFcb,LastThread,MinirdrCtx2; ULONG_PTR MatchFcb = 0x1badf00d; pRxActiveContexts = pListEntry = (PLIST_ENTRY)GetExpression("rdpdr!RxActiveContexts"); if( args && *args ) { MatchFcb = GetExpression( args ); } dprintf("\n Firstplentry: %08lx\n", pListEntry); for (;;) { if (!wGetData((ULONG_PTR)pListEntry,&LEbuffer,sizeof(LEbuffer),"RxActiveContexts")) return; if (LEbuffer.Flink == pRxActiveContexts) { if (pRxActiveContexts == pListEntry){ dprintf("Active RxContext List Empty!\n"); } return; } RxContext = ((ULONG_PTR)LEbuffer.Flink)-FieldOffsetOfContextListEntryInRxC(); CapturedFcb = LastThread = 0x0badf00d; ReadRxContextFields(RxContext,&CapturedFcb,&LastThread,&MinirdrCtx2); if (MatchFcb == 0x1badf00d) { dprintf("%08lx: %08lx %08lx: %08lx %08lx %08lx %08lx\n", pListEntry, LEbuffer.Flink,LEbuffer.Blink,RxContext,CapturedFcb,LastThread,MinirdrCtx2); } else if ((MatchFcb == CapturedFcb) || (MatchFcb == LastThread) ) { // if a matchfcb is specified and we have a match, the print and dump char Bufferqq[100]; dprintf("%08lx: %08lx %08lx: %08lx %08lx %08lx %08lx\n", pListEntry, LEbuffer.Flink,LEbuffer.Blink,RxContext,CapturedFcb,LastThread,MinirdrCtx2); sprintf(Bufferqq," %08lx ",RxContext); dump( hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, Bufferqq ); } pListEntry = LEbuffer.Flink; } } #define GV_dprintf(__FORMAT__,__NAME__,__VALUE__) { \ dprintf( "%s%-30s %08lx " __FORMAT__ "%s", \ c&1 ? " " : "", \ __NAME__, \ dwAddress, \ __VALUE__, \ c&1 ? "\n" : "" ); \ } DECLARE_API( gv ) { ULONG_PTR dwAddress; CHAR buf[ 100 ]; int i; int c=0; //CODE.IMPROVEMENT maybe we should hallucinate the moduleprefix instead // of having to specify it //CODE.IMPROVEMENT if we're not doing that, we shouldn't copy the name! //cause stuff to be loaded before we start printing dwAddress = GetExpression( "rdpdr!RxExpCXR" ); dwAddress = GetExpression( "mrxsmb!SmbMmExchangesInUse" ); for( i=0; GlobalBool[i]; i++, c++ ) { BOOL b; strcpy( &buf[0], GlobalBool[i] ); dwAddress = GetExpression( buf ); if( dwAddress == 0 ) { ERRPRT( "Unable to get address of %s\n", GlobalBool[i] ); continue; } if( !wGetData( dwAddress,&b, sizeof(b), "global BOOL") ) continue; GV_dprintf("%10s",GlobalBool[i],(b ? " TRUE" : "FALSE")); } for( i=0; GlobalShort[i]; i++, c++ ) { SHORT s; strcpy( &buf[0], GlobalShort[i] ); dwAddress = GetExpression( buf ); if( dwAddress == 0 ) { ERRPRT( "Unable to get address of %s\n", GlobalShort[i] ); continue; } if( !wGetData( dwAddress,&s,sizeof(s), "global SHORT") ) continue; GV_dprintf("%10d",GlobalShort[i],s); } for( i=0; GlobalLong[i]; i++, c++ ) { LONG l; strcpy( &buf[0], GlobalLong[i] ); dwAddress = GetExpression( buf ); if( dwAddress == 0 ) { ERRPRT( "Unable to get address of %s\n", GlobalLong[i] ); continue; } if( !wGetData( dwAddress,&l, sizeof(l), "global LONG") ) continue; GV_dprintf("%10d",GlobalLong[i],l); } for( i=0; GlobalPtrs[i]; i++, c++ ) { LONG l; //ERRPRT( "zaaaaa %s\n", GlobalPtrs[i] ); strcpy( &buf[0], GlobalPtrs[i] ); dwAddress = GetExpression( buf ); //ERRPRT( "zbbbbb %s %08lx\n", GlobalPtrs[i], dwAddress ); if( dwAddress == 0 ) { ERRPRT( "Unable to get address of %s\n", GlobalPtrs[i] ); continue; } if( !wGetData( dwAddress,&l, sizeof(l), "global PTR") ) continue; //ERRPRT( "zccccc %s %08lx\n", GlobalPtrs[i], dwAddress ); GV_dprintf(" %08lx",GlobalPtrs[i],l); } dprintf( "\n" ); } HANDLE DumpFile; CHAR wwDumpFormat[] = "-%06d: %s\n"; VOID DumpRoutine( ULONG EntryNumber, PSZ OriginalStringToPrint ) { UCHAR Buffer[200]; UCHAR StringToPrint[160]; PUCHAR p,q,r; LONG i; ULONG n,l3,l2,l1,l0; UCHAR Numbuf[32]; ULONG ReturnedSize; //dprintf("before %d\n",EntryNumber); for (p=(PUCHAR)OriginalStringToPrint,q=StringToPrint,i=160;;) { PSZ format=NULL; if (*p==0) break; if (*p==0x4) { format = "%lx"; } else if (*p==0x5) { format = "%ld"; } else if (*p < ' ') { p++;i--;continue; } if (format!=NULL) { LONG Length; //translate the number p++; l0=*p++; l1=(*p++)<<8; l2=(*p++)<<16; l3=(*p++)<<24; n = l0 + l1 + l2 + l3; //dprintf("yaya %d %08lx %08lx %08lx %08lx %08lx\n",n,n,l0,l1,l2,l3); Length = sprintf((char *)Numbuf,format,n); if (Length <= i) { for (r=Numbuf;*r;) { *q++ = *r++; } i -= Length; } else { i = 0; } if (i>0) continue; } if (i<=0) break; *q++ = *p++; i--; } *q = 0; //dprintf("after %d\n",EntryNumber); if (DumpFile == INVALID_HANDLE_VALUE) { dprintf(wwDumpFormat,EntryNumber,StringToPrint); return; } sprintf((char *)Buffer,wwDumpFormat,EntryNumber,StringToPrint); WriteFile(DumpFile,Buffer,strlen((char *)Buffer),&ReturnedSize,NULL); //should i check?? return; } DECLARE_API( lg ) { ULONG_PTR dwAddress; BYTE DataBuffer[MAX_RX_LOG_ENTRY_SIZE]; BYTE AlternateLine[110]; RX_LOG RxLog; ULONG LogEntries = 30; BOOLEAN LogEntriesSpecified = FALSE; PRX_LOG_ENTRY_HEADER CurrentEntry; //SETCALLBACKS(); dwAddress = GetExpression("rdpdr!s_RxLog"); if (!wGetData(dwAddress,&RxLog,sizeof(RX_LOG),"RxLog")) return; DumpFile = INVALID_HANDLE_VALUE; if( args && *args ) { LPSTR lpArgs; for (;*args;) { if (*args=='@') { break;} if ((*args>='0') && (*args<='9')) { sscanf(args,"%ld",&LogEntries); LogEntriesSpecified = TRUE; break; } args++; } lpArgs = strpbrk(args, "@"); if (lpArgs) { DumpFile = CreateFileA(lpArgs+1, GENERIC_READ|GENERIC_WRITE,0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE); if (DumpFile == INVALID_HANDLE_VALUE){ ULONG rc = LOWORD(GetLastError()); dprintf("Error Opening <%s> is %d.",lpArgs+1,rc); return; } if (!LogEntriesSpecified) { LogEntries = 99999999; //this will be reset to the right size } } } // Dump the log header followed by the log entries ... dprintf("s_RxLog.State %lx\n",RxLog.State); dprintf("s_RxLog.CurrentEntry %lx\n",RxLog.CurrentEntry); dprintf("s_RxLog.BaseEntry %lx\n",RxLog.BaseEntry); dprintf("s_RxLog.EntryLimit %lx\n",RxLog.EntryLimit); dprintf("s_RxLog.LogBufferSizeInEntries %ld\n",RxLog.LogBufferSizeInEntries); dprintf("s_RxLog.NumberOfEntriesIgnored %ld\n",RxLog.NumberOfEntriesIgnored); dprintf("s_RxLog.NumberOfLogWriteAttempts %ld\n",RxLog.NumberOfLogWriteAttempts); dprintf("s_RxLog.NumberOfLogWraps %ld\n",RxLog.NumberOfLogWraps); if (LogEntries > RxLog.LogBufferSizeInEntries) { LogEntries = RxLog.LogBufferSizeInEntries; } if (LogEntries < 1) { LogEntries = 1; } CurrentEntry = RxLog.CurrentEntry; CurrentEntry -= (LogEntries-1); if (CurrentEntry < RxLog.BaseEntry) { CurrentEntry += (RxLog.EntryLimit - RxLog.BaseEntry); } for (;;) { ULONG TextPtr; BOOLEAN ExtraOrdinaryLogEntry; LogEntries--; if ( CheckControlC() ) { return; } if (!wGetData((ULONG_PTR)CurrentEntry,&TextPtr,sizeof(TextPtr),"TextPtr")) return; if (!wGetData(TextPtr,&DataBuffer[0],sizeof(DataBuffer),"LogEntryBuffer")) return; ExtraOrdinaryLogEntry = (DataBuffer[0] == '#')&&(DataBuffer[1] == '>')&&(DataBuffer[3] == 0); if (!ExtraOrdinaryLogEntry) { //dprintf("-%06d: %s\n",LogEntries,DataBuffer); DumpRoutine(LogEntries,(char *)DataBuffer); } else { ULONG BinaryArgs = DataBuffer[2]-'0'; PULONG_PTR x = (PULONG_PTR)&DataBuffer[sizeof(ULONG_PTR)]; char Buffers[12*100]; //CODE.IMPROVEMENT this is stupid but effective ULONG i; ULONG_PTR BinaryStringMask; PSZ ffFormat; //dprintf("textptr = %08lx, binaryString = %08lx\n", TextPtr, x[0]); for (i=1,BinaryStringMask=x[0];i<=BinaryArgs;i++) { if (BinaryStringMask & (1<<(i-1))) { //dprintf("Stringing %d\n",i); wGetString(x[i],&Buffers[i*100]); //this could fail!!!! x[i] = ((ULONG_PTR)&Buffers[i*100]); //dprintf(" string is %s\n",x[i]); } } ffFormat = (PSZ)(x[1]); switch (BinaryArgs) { case 9: sprintf((char *)AlternateLine,ffFormat,x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9]); break; case 8: sprintf((char *)AlternateLine,ffFormat,x[2],x[3],x[4],x[5],x[6],x[7],x[8]); break; case 7: sprintf((char *)AlternateLine,ffFormat,x[2],x[3],x[4],x[5],x[6],x[7]); break; case 6: sprintf((char *)AlternateLine,ffFormat,x[2],x[3],x[4],x[5],x[6]); break; case 5: sprintf((char *)AlternateLine,ffFormat,x[2],x[3],x[4],x[5]); break; case 4: sprintf((char *)AlternateLine,ffFormat,x[2],x[3],x[4]); break; case 3: sprintf((char *)AlternateLine,ffFormat,x[2],x[3]); break; case 2: sprintf((char *)AlternateLine,ffFormat,x[2]); break; case 1: sprintf((char *)AlternateLine,ffFormat); break; } DumpRoutine(LogEntries,(char *)AlternateLine); } if (LogEntries==0) break; CurrentEntry++; if (CurrentEntry==RxLog.EntryLimit) { CurrentEntry = RxLog.BaseEntry; } } if (DumpFile != INVALID_HANDLE_VALUE) { CloseHandle(DumpFile); DumpFile = INVALID_HANDLE_VALUE; } } PCWSTR ExtensionLib = NULL; HANDLE hExtensionMod = NULL; ULONG DebugeeArchitecture = 0; PCWSTR GetExtensionLibPerDebugeeArchitecture(ULONG DebugeeArchitecture); PWINDBG_EXTENSION_ROUTINE GetKdExtProcAddress( IN PCSTR FuncName ) { PWINDBG_EXTENSION_ROUTINE WindbgExtRoutine = NULL; //dprintf( "yaya\n"); if (hExtensionMod == NULL) { if (DebugeeArchitecture == 0) { ULONG_PTR pArchitecture; ReloadSymbols(" rdbss.sys"); pArchitecture = GetExpression("rdpdr!RxProcessorArchitecture"); if (pArchitecture==0) { dprintf("couldn't get architecture value...\n"); return NULL; } if (!wGetData(pArchitecture,&DebugeeArchitecture,sizeof(DebugeeArchitecture),"RxArch")) return NULL; if ((DebugeeArchitecture&0x0fff0000) != 0xabc0000) { dprintf("\n Bad DebugeeArchitecture %08lx\n", DebugeeArchitecture); return(NULL); } DebugeeArchitecture &= 0xffff; } ExtensionLib = GetExtensionLibPerDebugeeArchitecture(DebugeeArchitecture); if (ExtensionLib == NULL) { dprintf( "bad debuggee arch\n"); return(NULL); } hExtensionMod = LoadLibrary( ExtensionLib ); if (hExtensionMod == NULL) { dprintf( "couldn't load %ws\n", ExtensionLib ); return(NULL); } } WindbgExtRoutine = (PWINDBG_EXTENSION_ROUTINE)GetProcAddress( (HINSTANCE)hExtensionMod, FuncName ); if (WindbgExtRoutine == NULL) { dprintf( "couldn't find %ws%s\n", ExtensionLib, FuncName ); } return WindbgExtRoutine; } #define CALL_THRU(NAME,ARGS) { \ PWINDBG_EXTENSION_ROUTINE WindbgExtRoutine = GetKdExtProcAddress(NAME); \ if (WindbgExtRoutine != NULL) { \ (WindbgExtRoutine)( hCurrentProcess, \ hCurrentThread, \ dwCurrentPc, \ dwProcessor, \ ARGS \ ); \ } \ } DECLARE_API( testr ) { CALL_THRU ( "threadfields", ""); } DECLARE_API( dump ); VOID __FollowOnHelper ( PFOLLOWON_HELPER_ROUTINE Callee, HANDLE hCurrentProcess, HANDLE hCurrentThread, ULONG dwCurrentPc, ULONG dwProcessor, PCSTR args ) { BYTE Name[100], Buffer2[200]; FOLLOWON_HELPER_RETURNS ret; PPERSISTENT_RDPDRKD_INFO p; p = LocatePersistentInfoFromView(); if (!p) { dprintf("Couldn't allocate perstistent info buffer...sorry...\n"); return; } ret = Callee(p,Name,Buffer2); if (p!= NULL) FreePersistentInfoView(p); p = NULL; switch (ret) { case FOLLOWONHELPER_DUMP: dump(hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, (char *)Buffer2 ); break; case FOLLOWONHELPER_CALLTHRU: CALL_THRU ( (char *)Name, (char *)Buffer2); break; case FOLLOWONHELPER_ERROR: dprintf("%s",Buffer2); break; case FOLLOWONHELPER_DONE: break; } return; } #define FollowOnHelper(a) { \ __FollowOnHelper(a, \ hCurrentProcess, \ hCurrentThread, \ dwCurrentPc, \ dwProcessor, \ args); \ } DECLARE_FOLLOWON_HELPER_CALLEE(FcbFollowOn); DECLARE_API( fcb ) { FollowOnHelper(FcbFollowOn); } DECLARE_API( flags ) { ULONG i,mask,newline,value; if( args && *args ) { sscanf(args,"%lx",&value); dprintf("Flags for %08lx\n",value); } else { dprintf("error in flags: no value presented\n"); return; } for (i=newline=0,mask=1;i<32;i++,mask<<=1) { if (value&mask) { dprintf(" %02d 0x%08lx%c",i,mask,(newline==0)?' ':'\n'); newline ^= 1; } } if (newline) { dprintf("\n"); } } DECLARE_API( cxr ) { ULONG_PTR dwAddress,cxr; BYTE NumBuffer[16]; RX_LOG RxLog; ULONG LogEntries = 30; PRX_LOG_ENTRY_HEADER CurrentEntry; //SETCALLBACKS(); dwAddress = GetExpression("rdpdr!RxExpCXR"); if (!wGetData(dwAddress,&cxr,sizeof(cxr),"cxr")) return; dprintf("\nRxExpCXR=%08lx\n",cxr); sprintf((char *)NumBuffer,"%08lx \n",cxr); CALL_THRU ( "cxr", (char *)NumBuffer); if (DebugeeArchitecture==0) { CALL_THRU ( "kb", ""); } } VOID dprintfsprintfbuffer(BYTE *Buffer) { dprintf("%s\n",Buffer); } DECLARE_API(ddd); #if DBG VOID ListRefs(ULONG_PTR dwAddress, BOOL ShowStack, HANDLE hCurrentProcess, HANDLE hCurrentThread, ULONG dwCurrentPc, ULONG dwProcessor) { ULONG_PTR dwRecordListAddr; ULONG_PTR dwCurrentAddr; ULONG_PTR dwAddr; ReferenceTraceRecord CurrentRecord; ULONG_PTR dwTotalRefs; ULONG_PTR dwRefs; ULONG_PTR dwRefsPrinted; char szObjectName[32]; dwRecordListAddr = GetExpression("rdpdr!RefCount___TraceRecordList"); if (dwRecordListAddr == 0) { dprintf("Unable to get address of rdpdr!RefCount___TraceRecordList\n"); return; } dwAddr = GetExpression("rdpdr!RefCount___dwReferenceTraceIndex"); if (dwAddr == 0) { dprintf("Unable to get address of rdpdr!RefCount___dwReferenceTraceIndex\n"); return; } if (!wGetData(dwAddr, &dwTotalRefs, sizeof(dwTotalRefs), "ULONG_PTR")) { return; } if (dwAddress != 0xFFFFFFFF) { dprintf("dumping references to object %p\n", dwAddress); } dprintf("TraceRecord References ObjectPointer ObjectType\n"); dwCurrentAddr = dwRecordListAddr; dwRefs = 0; dwRefsPrinted = 0; while(dwRefs < dwTotalRefs && dwCurrentAddr < dwRecordListAddr + sizeof(RefCount::_TraceRecordList)) { if (wGetData(dwCurrentAddr, &CurrentRecord, sizeof(CurrentRecord), "ReferenceTraceRecord")) { if (wGetData((ULONG_PTR)CurrentRecord.ClassName, &szObjectName, sizeof(szObjectName), "Object Name")) { szObjectName[sizeof(szObjectName) - 1] = 0; } else { szObjectName[0] = 0; } if (dwAddress == 0xFFFFFFFF || (ULONG_PTR)CurrentRecord.pRefCount == dwAddress) { dprintf("%p %p %p %s\n", dwCurrentAddr, CurrentRecord.refs, CurrentRecord.pRefCount, szObjectName); dwRefsPrinted++; if (ShowStack) { char szCmd[32]; sprintf(szCmd, "ReferenceTraceRecord@%p", dwCurrentAddr); ddd(hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor, szCmd); } } } else { break; } dwCurrentAddr += sizeof(CurrentRecord); dwRefs++; } dprintf("Printed %ld of %ld paged in objects of %ld records\n", dwRefsPrinted, dwRefs, dwTotalRefs); } #endif DECLARE_API( trc ) { #if DBG ULONG_PTR dwRecentTracesAddr; ULONG_PTR dwCurrentMsgAddr; ULONG_PTR dwCurrentAddr; ULONG_PTR dwCurrentMsg; ULONG_PTR dwFirstLine; ULONG_PTR dwFinalLine; ULONG_PTR dwCurrentLine; ULONG_PTR dwLinesToPrint; ULONG_PTR dwLines = 0; char szTraceLine[TRC_BUFFER_SIZE]; if (!ParseTrc(args, &dwLines)) { return; } dwRecentTracesAddr = GetExpression("rdpdr!TRC_RecentTraces"); if (dwRecentTracesAddr == 0) { dprintf("Unable to get address of rdpdr!TRC_RecentTraces\n"); return; } dwCurrentMsgAddr = GetExpression("rdpdr!TRC_CurrentMsg"); if (dwCurrentMsgAddr == 0) { dprintf("Unable to get address of rdpdr!TRC_CurrentMsg\n"); return; } // // Look up how many traces have been done // if (!wGetData(dwCurrentMsgAddr, &dwCurrentMsg, sizeof(dwCurrentMsg), "ULONG_PTR")) { return; } if (dwCurrentMsg == 0xFFFFFFFF) { dprintf("No tracing\n"); return; } dprintf("Total Traces: %ld\n", dwCurrentMsg); if (dwCurrentMsg > TRC_RamMsgMask) { // // We wrapped at least once // dwFirstLine = (dwCurrentMsg + 1) & TRC_RamMsgMask; dwFinalLine = (dwCurrentMsg) & TRC_RamMsgMask; dwLinesToPrint = TRC_RamMsgMax; } else { dwFirstLine = 0; dwFinalLine = dwCurrentMsg; dwLinesToPrint = dwFinalLine + 1; } if (dwLinesToPrint > dwLines) { // Advance first line by the difference dwFirstLine = (dwFirstLine + (dwLinesToPrint - dwLines)) & TRC_RamMsgMask; // Adjust number of lines downward dwLinesToPrint = dwLines; } dwCurrentLine = dwFirstLine; while(dwLinesToPrint > 0) { dwCurrentAddr = dwRecentTracesAddr + dwCurrentLine * TRC_BUFFER_SIZE; if (wGetData(dwCurrentAddr, &szTraceLine[0], sizeof(szTraceLine), "TraceLine")) { dprintf("%s", szTraceLine); } else { break; } dwCurrentLine = (dwCurrentLine + 1) & TRC_RamMsgMask; dwLinesToPrint--; } #endif } #if DBG BOOL ParseTrc(PCSTR args, DWORD *dwLines) { PCSTR p = args; enum tagParseState { Nominal, Usage, PostMinus, StartLines, Lines } ParseState = Nominal; DWORD LinesT = 0; if (args == NULL) { return TRUE; } while (ParseState != Usage && *p) { switch(ParseState) { case Nominal: switch (*p) { case '-': ParseState = PostMinus; break; case ' ': case '\t': break; default: ParseState = Usage; } break; case PostMinus: switch (*p) { case 'l': ParseState = StartLines; break; default: ParseState = Usage; } break; case Lines: case StartLines: int i; i = (*p) - '0'; if (i >= 0 && i <= 9) { // // Now past initial whitespace // ParseState = Lines; LinesT *= 10; LinesT += i; } else { switch (*p) { case ' ': case '\t': if (ParseState == Lines) { // Must be done ParseState = Nominal; } // else skip initial whitespace break; default: ParseState = Usage; } } break; } p++; } if (ParseState == Usage) { dprintf("Error in arguments: %s\n", args); dprintf(" %*c\n", p - args, '^'); dprintf("usage: trc [-l] []\n\n"); dprintf(" numlines: number of lines to trace\n"); return FALSE; } else { *dwLines = LinesT; return TRUE; } } #endif // DBG DECLARE_API( listref ) { ULONG_PTR RefObj = 0xFFFFFFFF; if( args && *args ) { RefObj = GetExpression( args ); } #if DBG ListRefs(RefObj, FALSE, hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor); #endif } DECLARE_API( listreff ) { ULONG_PTR RefObj = 0xFFFFFFFF; if( args && *args ) { RefObj = GetExpression( args ); } #if DBG ListRefs(RefObj, TRUE, hCurrentProcess, hCurrentThread, dwCurrentPc, dwProcessor); #endif }