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.
1152 lines
32 KiB
1152 lines
32 KiB
/*++
|
|
|
|
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 <ntos.h>
|
|
#include <nturtl.h>
|
|
#include "ntverp.h"
|
|
|
|
#include <windows.h>
|
|
#include <wdbgexts.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include <kdextlib.h>
|
|
#include <rdpdrkd.h>
|
|
|
|
#include <ntrxdef.h>
|
|
#include <rxtypes.h>
|
|
extern "C" {
|
|
#include <rxlog.h>
|
|
}
|
|
|
|
#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 <Struct Type Name>@<address expr> ",
|
|
"listref [address of specific RefCount object]"
|
|
"ddd <address expr> -- dump using context"
|
|
"columns <d> -- controls the number of columns in the display ",
|
|
"lg [<logentries>][@filename] -- dump the log",
|
|
"gv -- dump out important variables",
|
|
"activerx [fcbtomatch]-- dump the list of active contexts",
|
|
"flags <value>-- 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] [<numlines>]\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
|
|
}
|