449 lines
9.4 KiB
C
449 lines
9.4 KiB
C
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
|
|
#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>
|
|
|
|
|
|
|
|
|
|
WINDBG_EXTENSION_APIS ExtensionApis;
|
|
EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
|
|
|
|
#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;
|
|
}
|
|
|
|
BOOL
|
|
wPrintStringW( IN LPSTR msg OPTIONAL, IN PUNICODE_STRING pStr, IN BOOL nl )
|
|
{
|
|
UNICODE_STRING NewStr;
|
|
|
|
ULONG BytesRead;
|
|
|
|
if( msg )
|
|
dprintf( msg );
|
|
|
|
if( pStr->Length == 0 ) {
|
|
if( nl )
|
|
dprintf( "\n" );
|
|
return TRUE;
|
|
}
|
|
|
|
NewStr.Buffer = (WCHAR *)LocalAlloc( LPTR, pStr->Length + 1 );
|
|
NewStr.Length = pStr->Length;
|
|
NewStr.MaximumLength = pStr->Length+1;
|
|
if( NewStr.Buffer == NULL ) {
|
|
ERRPRT( "Out of memory!\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
ReadMemory( (ULONG_PTR)pStr->Buffer,
|
|
NewStr.Buffer,
|
|
pStr->Length,
|
|
&BytesRead );
|
|
|
|
if ( BytesRead ) {
|
|
dprintf("%wZ%s", &NewStr, nl ? "\n" : "" );
|
|
}
|
|
|
|
LocalFree((HLOCAL)NewStr.Buffer);
|
|
|
|
return BytesRead;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Fetches the data at the given address
|
|
*/
|
|
BOOLEAN
|
|
wGetData( ULONG_PTR dwAddress, PVOID ptr, ULONG size)
|
|
{
|
|
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);
|
|
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) ){
|
|
//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;
|
|
|
|
SavedMajorVersion = MajorVersion;
|
|
SavedMinorVersion = MinorVersion;
|
|
ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
ULONG FieldOffsetOfContextListEntryInRxC();
|
|
VOID ReadRxContextFields(ULONG_PTR RxContext,PULONG_PTR pFcb,PULONG_PTR pThread, PULONG_PTR pMiniCtx2);
|
|
DECLARE_API( dump );
|
|
|
|
|
|
|
|
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=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(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(Buffer,wwDumpFormat,EntryNumber,StringToPrint);
|
|
WriteFile(DumpFile,Buffer,strlen(Buffer),&ReturnedSize,NULL);
|
|
//should i check??
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
PCWSTR ExtensionLib = NULL;
|
|
HANDLE hExtensionMod = NULL;
|
|
ULONG DebugeeArchitecture = 0;
|
|
|
|
PCWSTR GetExtensionLibPerDebugeeArchitecture(ULONG DebugeeArchitecture);
|
|
|
|
|
|
DECLARE_API( dump );
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
VOID dprintfsprintfbuffer(BYTE *Buffer)
|
|
{
|
|
dprintf("%s\n",Buffer);
|
|
}
|
|
|
|
BOOL
|
|
wPrintLargeInt(
|
|
LARGE_INTEGER *bigint)
|
|
{
|
|
dprintf( "%08x:%08x", bigint->HighPart, bigint->LowPart);
|
|
return( TRUE );
|
|
}
|