413 lines
7.7 KiB
C
413 lines
7.7 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
kdextlib.c
|
||
|
||
Abstract:
|
||
|
||
Library routines for dumping data structures given a meta level descrioption
|
||
|
||
Author:
|
||
|
||
Balan Sethu Raman (SethuR) 11-May-1994
|
||
|
||
Notes:
|
||
The implementation tends to avoid memory allocation and deallocation as much as possible.
|
||
Therefore We have choosen an arbitrary length as the default buffer size. A mechanism will
|
||
be provided to modify this buffer length through the debugger extension commands.
|
||
|
||
Revision History:
|
||
|
||
11-Nov-1994 SethuR Created
|
||
|
||
--*/
|
||
|
||
#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>
|
||
|
||
BOOL
|
||
kdextAtoi(
|
||
LPSTR lpArg,
|
||
int *pRet
|
||
);
|
||
|
||
int
|
||
kdextStrlen(
|
||
LPSTR lpsz
|
||
);
|
||
|
||
int
|
||
kdextStrnicmp(
|
||
LPSTR lpsz1,
|
||
LPSTR lpsz2,
|
||
int cLen
|
||
);
|
||
|
||
#define PRINTF dprintf
|
||
|
||
|
||
PWINDBG_OUTPUT_ROUTINE lpOutputRoutine;
|
||
PWINDBG_GET_EXPRESSION32 lpGetExpressionRoutine;
|
||
PWINDBG_GET_SYMBOL32 lpGetSymbolRoutine;
|
||
PWINDBG_READ_PROCESS_MEMORY_ROUTINE lpReadMemoryRoutine;
|
||
|
||
#define NL 1
|
||
#define NONL 0
|
||
|
||
#define DEFAULT_UNICODE_DATA_LENGTH 512
|
||
USHORT s_UnicodeStringDataLength = DEFAULT_UNICODE_DATA_LENGTH;
|
||
WCHAR s_UnicodeStringData[DEFAULT_UNICODE_DATA_LENGTH];
|
||
WCHAR *s_pUnicodeStringData = s_UnicodeStringData;
|
||
|
||
#define DEFAULT_ANSI_DATA_LENGTH 512
|
||
USHORT s_AnsiStringDataLength = DEFAULT_ANSI_DATA_LENGTH;
|
||
CHAR s_AnsiStringData[DEFAULT_ANSI_DATA_LENGTH];
|
||
CHAR *s_pAnsiStringData = s_AnsiStringData;
|
||
|
||
//
|
||
// No. of columns used to display struct fields;
|
||
//
|
||
|
||
ULONG s_MaxNoOfColumns = 3;
|
||
ULONG s_NoOfColumns = 1;
|
||
|
||
/*
|
||
* Fetches the data at the given address
|
||
*/
|
||
BOOLEAN
|
||
GetData( ULONG_PTR dwAddress, PVOID ptr, ULONG size)
|
||
{
|
||
BOOL b;
|
||
ULONG BytesRead;
|
||
|
||
b = (lpReadMemoryRoutine)(dwAddress, ptr, size, &BytesRead );
|
||
|
||
|
||
if (!b || BytesRead != size ) {
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* Fetch the null terminated ASCII string at dwAddress into buf
|
||
*/
|
||
BOOL
|
||
GetStringW( DWORD dwAddress, LPWSTR buf )
|
||
{
|
||
do {
|
||
if( !GetData( dwAddress,buf, sizeof(WCHAR)) )
|
||
return FALSE;
|
||
|
||
dwAddress += sizeof(WCHAR);
|
||
buf++;
|
||
|
||
} while( *buf != '\0' );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* Displays a byte in hexadecimal
|
||
*/
|
||
VOID
|
||
PrintHexChar( UCHAR c )
|
||
{
|
||
PRINTF( "%c%c", "0123456789abcdef"[ (c>>4)&7 ], "0123456789abcdef"[ c&7 ] );
|
||
}
|
||
|
||
/*
|
||
* Displays a buffer of data in hexadecimal
|
||
*/
|
||
VOID
|
||
PrintHexBuf( PUCHAR buf, ULONG cbuf )
|
||
{
|
||
while( cbuf-- ) {
|
||
PrintHexChar( *buf++ );
|
||
PRINTF( " " );
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Displays a unicode string
|
||
*/
|
||
BOOL
|
||
PrintStringW(LPSTR msg, PUNICODE_STRING puStr, BOOL nl )
|
||
{
|
||
UNICODE_STRING UnicodeString;
|
||
BOOLEAN b;
|
||
|
||
if( msg )
|
||
PRINTF( msg );
|
||
|
||
if( puStr->Length == 0 ) {
|
||
if( nl )
|
||
PRINTF( "\n" );
|
||
return TRUE;
|
||
}
|
||
|
||
UnicodeString.Buffer = s_pUnicodeStringData;
|
||
UnicodeString.MaximumLength = s_UnicodeStringDataLength;
|
||
UnicodeString.Length = (puStr->Length > s_UnicodeStringDataLength)
|
||
? s_UnicodeStringDataLength
|
||
: puStr->Length;
|
||
|
||
b = GetData((ULONG_PTR)puStr->Buffer, UnicodeString.Buffer, (ULONG) UnicodeString.Length);
|
||
|
||
if (b) {
|
||
PRINTF("%wZ%s", &UnicodeString, nl ? "\n" : "" );
|
||
}
|
||
|
||
return b;
|
||
}
|
||
|
||
/*
|
||
* Displays a ANSI string
|
||
*/
|
||
BOOL
|
||
PrintStringA(LPSTR msg, PANSI_STRING pStr, BOOL nl )
|
||
{
|
||
ANSI_STRING AnsiString;
|
||
BOOL b;
|
||
|
||
if( msg )
|
||
PRINTF( msg );
|
||
|
||
if( pStr->Length == 0 ) {
|
||
if( nl )
|
||
PRINTF( "\n" );
|
||
return TRUE;
|
||
}
|
||
|
||
AnsiString.Buffer = s_pAnsiStringData;
|
||
AnsiString.MaximumLength = s_AnsiStringDataLength;
|
||
AnsiString.Length = (pStr->Length > (s_AnsiStringDataLength - 1))
|
||
? (s_AnsiStringDataLength - 1)
|
||
: pStr->Length;
|
||
|
||
b = (lpReadMemoryRoutine)(
|
||
(ULONG_PTR)pStr->Buffer,
|
||
AnsiString.Buffer,
|
||
AnsiString.Length,
|
||
NULL);
|
||
|
||
if (b) {
|
||
AnsiString.Buffer[ AnsiString.Length ] = '\0';
|
||
PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" );
|
||
}
|
||
|
||
return b;
|
||
}
|
||
|
||
/*
|
||
* Displays a GUID
|
||
*/
|
||
|
||
BOOL
|
||
PrintGuid(
|
||
GUID *pguid)
|
||
{
|
||
ULONG i;
|
||
|
||
PRINTF( "%08x-%04x-%04x", pguid->Data1, pguid->Data2, pguid->Data3 );
|
||
for (i = 0; i < 8; i++) {
|
||
PRINTF("%02x",pguid->Data4[i]);
|
||
}
|
||
return( TRUE );
|
||
}
|
||
|
||
/*
|
||
* Displays a LARGE_INTEGER
|
||
*/
|
||
|
||
BOOL
|
||
PrintLargeInt(
|
||
LARGE_INTEGER *bigint)
|
||
{
|
||
PRINTF( "%08x:%08x", bigint->HighPart, bigint->LowPart);
|
||
return( TRUE );
|
||
}
|
||
|
||
/*
|
||
* Displays all the fields of a given struct. This is the driver routine that is called
|
||
* with the appropriate descriptor array to display all the fields in a given struct.
|
||
*/
|
||
|
||
|
||
|
||
LPSTR LibCommands[] = {
|
||
"help -- This command ",
|
||
"version -- Version of extension ",
|
||
"dump <Struct Type Name>@<address expr> ",
|
||
"columns <d> -- controls the number of columns in the display ",
|
||
0
|
||
};
|
||
|
||
BOOL
|
||
help(
|
||
DWORD dwCurrentPC,
|
||
PWINDBG_EXTENSION_APIS lpExtensionApis,
|
||
LPSTR lpArgumentString
|
||
)
|
||
{
|
||
int i;
|
||
|
||
|
||
PRINTF("\n");
|
||
|
||
for( i=0; ExtensionNames[i]; i++ )
|
||
PRINTF( "%s\n", ExtensionNames[i] );
|
||
|
||
for( i=0; LibCommands[i]; i++ )
|
||
PRINTF( " %s\n", LibCommands[i] );
|
||
|
||
for( i=0; Extensions[i]; i++) {
|
||
PRINTF( " %s\n", Extensions[i] );
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL
|
||
columns(
|
||
DWORD dwCurrentPC,
|
||
PWINDBG_EXTENSION_APIS lpExtensionApis,
|
||
LPSTR lpArgumentString
|
||
)
|
||
{
|
||
ULONG NoOfColumns;
|
||
int i;
|
||
|
||
|
||
if (kdextAtoi(lpArgumentString, &i) && i > 0) {
|
||
|
||
NoOfColumns = (ULONG) i;
|
||
|
||
if (NoOfColumns > s_MaxNoOfColumns) {
|
||
PRINTF( "No. Of Columns exceeds maximum(%ld) -- directive Ignored\n", s_MaxNoOfColumns );
|
||
} else {
|
||
s_NoOfColumns = NoOfColumns;
|
||
}
|
||
|
||
} else {
|
||
|
||
PRINTF( "Bad argument to command (%s)", lpArgumentString );
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL
|
||
version
|
||
(
|
||
DWORD dwCurrentPC,
|
||
PWINDBG_EXTENSION_APIS lpExtensionApis,
|
||
LPSTR lpArgumentString
|
||
)
|
||
{
|
||
#if VER_DEBUG
|
||
char *kind = "checked";
|
||
#else
|
||
char *kind = "free";
|
||
#endif
|
||
|
||
|
||
PRINTF( "Mup debugger extension dll for %s build %u\n", kind, VER_PRODUCTBUILD );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/*
|
||
* KD Extensions should not link with the C-Runtime library routines. So,
|
||
* we implement a few of the needed ones here.
|
||
*/
|
||
|
||
BOOL
|
||
kdextAtoi(
|
||
LPSTR lpArg,
|
||
int *pRet
|
||
)
|
||
{
|
||
int n, cbArg, val = 0;
|
||
BOOL fNegative = FALSE;
|
||
|
||
cbArg = kdextStrlen( lpArg );
|
||
|
||
if (cbArg > 0) {
|
||
for (n = 0; lpArg[n] == ' '; n++) {
|
||
;
|
||
}
|
||
if (lpArg[n] == '-') {
|
||
n++;
|
||
fNegative = TRUE;
|
||
}
|
||
for (; lpArg[n] >= '0' && lpArg[n] <= '9'; n++) {
|
||
val *= 10;
|
||
val += (int) (lpArg[n] - '0');
|
||
}
|
||
if (lpArg[n] == 0) {
|
||
*pRet = (fNegative ? -val : val);
|
||
return( TRUE );
|
||
} else {
|
||
return( FALSE );
|
||
}
|
||
} else {
|
||
return( FALSE );
|
||
}
|
||
|
||
}
|
||
|
||
int
|
||
kdextStrlen(
|
||
LPSTR lpsz
|
||
)
|
||
{
|
||
int c;
|
||
|
||
if (lpsz == NULL) {
|
||
c = 0;
|
||
} else {
|
||
for (c = 0; lpsz[c] != 0; c++) {
|
||
;
|
||
}
|
||
}
|
||
|
||
return( c );
|
||
}
|
||
|
||
|
||
#define UPCASE_CHAR(c) \
|
||
( (((c) >= 'a') && ((c) <= 'z')) ? ((c) - 'a' + 'A') : (c) )
|
||
|
||
int
|
||
kdextStrnicmp(
|
||
LPSTR lpsz1,
|
||
LPSTR lpsz2,
|
||
int cLen
|
||
)
|
||
{
|
||
int nDif, i;
|
||
|
||
for (i = nDif = 0; nDif == 0 && i < cLen; i++) {
|
||
nDif = UPCASE_CHAR(lpsz1[i]) - UPCASE_CHAR(lpsz2[i]);
|
||
}
|
||
|
||
return( nDif );
|
||
}
|
||
|