diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nbt/nt/netbtkd/kdextlib.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/nbt/nt/netbtkd/kdextlib.c')
-rw-r--r-- | private/ntos/nbt/nt/netbtkd/kdextlib.c | 843 |
1 files changed, 843 insertions, 0 deletions
diff --git a/private/ntos/nbt/nt/netbtkd/kdextlib.c b/private/ntos/nbt/nt/netbtkd/kdextlib.c new file mode 100644 index 000000000..132d57b5d --- /dev/null +++ b/private/ntos/nbt/nt/netbtkd/kdextlib.c @@ -0,0 +1,843 @@ +/*++ + +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 <nt.h> +#include <ntrtl.h> +#include "ntverp.h" + +#define KDEXTMODE + +#include <windef.h> +#include <ntkdexts.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <kdextlib.h> + +PNTKD_OUTPUT_ROUTINE lpOutputRoutine; +PNTKD_GET_EXPRESSION lpGetExpressionRoutine; +PNTKD_GET_SYMBOL lpGetSymbolRoutine; +PNTKD_READ_VIRTUAL_MEMORY lpReadMemoryRoutine; + +#define PRINTF lpOutputRoutine +#define ERROR lpOutputRoutine + +#define NL 1 +#define NONL 0 + +#define SETCALLBACKS() \ + lpOutputRoutine = lpExtensionApis->lpOutputRoutine; \ + lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine; \ + lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine; \ + lpReadMemoryRoutine = lpExtensionApis->lpReadVirtualMemRoutine; + +#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( DWORD dwAddress, PVOID ptr, ULONG size) +{ + BOOL b; + ULONG BytesRead; + + b = (lpReadMemoryRoutine)((LPVOID) dwAddress, ptr, size, &BytesRead ); + + + if (!b || BytesRead != size ) { + return FALSE; + } + + return TRUE; +} + +/* + * Fetch the null terminated ASCII string at dwAddress into buf + */ +BOOL +GetString( DWORD dwAddress, PSZ buf ) +{ + do { + if( !GetData( dwAddress,buf, 1) ) + return FALSE; + + dwAddress++; + 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; + ANSI_STRING AnsiString; + 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 = (lpReadMemoryRoutine)( + (LPVOID) puStr->Buffer, + UnicodeString.Buffer, + UnicodeString.Length, + NULL); + + if (b) { + RtlUnicodeStringToAnsiString(&AnsiString, puStr, TRUE); + PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" ); + RtlFreeAnsiString(&AnsiString); + } + + return b; +} + +/* + * Displays a ANSI string + */ +BOOL +PrintStringA(LPSTR msg, PANSI_STRING pStr, BOOL nl ) +{ + ANSI_STRING AnsiString; + BOOLEAN 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)( + (LPVOID) pStr->Buffer, + AnsiString.Buffer, + AnsiString.Length, + NULL); + + if (b) { + AnsiString.Buffer[ AnsiString.Length ] = '\0'; + PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" ); + } + + return b; +} + +/* + * 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. + */ + +char *NewLine = "\n"; +char *FieldSeparator = " "; +char *DotSeparator = "."; +#define NewLineForFields(FieldNo) \ + ((((FieldNo) % s_NoOfColumns) == 0) ? NewLine : FieldSeparator) +#define FIELD_NAME_LENGTH 30 + +VOID +PrintStructFields( DWORD dwAddress, VOID *ptr, FIELD_DESCRIPTOR *pFieldDescriptors ) +{ + int i; + int j; + BYTE ch; + + // Display the fields in the struct. + for( i=0; pFieldDescriptors->Name; i++, pFieldDescriptors++ ) { + + // Indentation to begin the struct display. + PRINTF( " " ); + + if( strlen( pFieldDescriptors->Name ) > FIELD_NAME_LENGTH ) { + PRINTF( "%-17s...%s ", pFieldDescriptors->Name, pFieldDescriptors->Name+strlen(pFieldDescriptors->Name)-10 ); + } else { + PRINTF( "%-30s ", pFieldDescriptors->Name ); + } + + PRINTF( "(0x%-2X) ", pFieldDescriptors->Offset ); + + switch( pFieldDescriptors->FieldType ) { + case FieldTypeByte: + case FieldTypeChar: + PRINTF( "%-16d%s", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ), + NewLineForFields(i) ); + break; + + case FieldTypeBoolean: + PRINTF( "%-16s%s", + *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE", + NewLineForFields(i)); + break; + + case FieldTypeBool: + PRINTF( "%-16s%s", + *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE", + NewLineForFields(i)); + break; + + case FieldTypePointer: + PRINTF( "%-16X%s", + *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ), + NewLineForFields(i) ); + break; + + case FieldTypeULongULong: + PRINTF( "%d%s", + *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ), + FieldSeparator ); + PRINTF( "%d%s", + *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset + sizeof(ULONG)), + NewLineForFields(i) ); + break; + + case FieldTypeListEntry: + + if ( (ULONG)(dwAddress + pFieldDescriptors->Offset) == + *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset )) + { + PRINTF( "%s", "List Empty\n" ); + } + else + { + PRINTF( "%-8X%s", + *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ), + FieldSeparator ); + PRINTF( "%-8X%s", + *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset + sizeof(ULONG)), + NewLineForFields(i) ); + } + break; + + // Ip address: 4 bytes long + case FieldTypeIpAddr: + PRINTF( "%X%s", + *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ), + FieldSeparator ); + PRINTF( "(%d%s", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 3), + DotSeparator ); + PRINTF( "%d%s", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 2 ), + DotSeparator ); + PRINTF( "%d%s", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 1 ), + DotSeparator ); + PRINTF( "%d)%s", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ), + NewLineForFields(i) ); + break; + + // Mac address: 6 bytes long + case FieldTypeMacAddr: + for (j=0; j<5; j++) + { + PRINTF( "%X%s", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j), + FieldSeparator ); + } + PRINTF( "%X%s", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 5), + NewLineForFields(i) ); + break; + + // Netbios name: 16 bytes long + case FieldTypeNBName: + // + // if first byte is printable, print the first 15 bytes as characters + // and 16th byte as a hex value. otherwise, print all the 16 bytes + // as hex values + // + ch = *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset); + if (ch >= 0x20 && ch <= 0x7e) + { + for (j=0; j<15; j++) + { + PRINTF( "%c", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j)); + } + PRINTF( "<%X>%s", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 15), + NewLineForFields(i) ); + } + else + { + for (j=0; j<16; j++) + { + PRINTF( "%.2X", + *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j)); + } + PRINTF( "%s", NewLineForFields(i) ); + } + break; + + case FieldTypeULong: + case FieldTypeLong: + PRINTF( "%-16d%s", + *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ), + NewLineForFields(i) ); + break; + + case FieldTypeShort: + PRINTF( "%-16X%s", + *(SHORT *)(((char *)ptr) + pFieldDescriptors->Offset ), + NewLineForFields(i) ); + break; + + case FieldTypeUShort: + PRINTF( "%-16X%s", + *(USHORT *)(((char *)ptr) + pFieldDescriptors->Offset ), + NewLineForFields(i) ); + break; + + case FieldTypeUnicodeString: + PrintStringW( NULL, (UNICODE_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL ); + PRINTF( NewLine ); + break; + + case FieldTypeAnsiString: + PrintStringA( NULL, (ANSI_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL ); + PRINTF( NewLine ); + break; + + case FieldTypeSymbol: + { + UCHAR SymbolName[ 200 ]; + ULONG Displacement; + PVOID sym = (PVOID)(*(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset )); + + lpGetSymbolRoutine( sym, SymbolName, &Displacement ); + PRINTF( "%-16s%s", + SymbolName, + NewLineForFields(i) ); + } + break; + + case FieldTypeEnum: + { + ULONG EnumValue; + ENUM_VALUE_DESCRIPTOR *pEnumValueDescr; + // Get the associated numericla value. + + EnumValue = *((ULONG *)((BYTE *)ptr + pFieldDescriptors->Offset)); + + if ((pEnumValueDescr = pFieldDescriptors->AuxillaryInfo.pEnumValueDescriptor) + != NULL) { + // + // An auxilary textual description of the value is + // available. Display it instead of the numerical value. + // + + LPSTR pEnumName = NULL; + + while (pEnumValueDescr->EnumName != NULL) { + if (EnumValue == pEnumValueDescr->EnumValue) { + pEnumName = pEnumValueDescr->EnumName; + break; + } + } + + if (pEnumName != NULL) { + PRINTF( "%-16s ", pEnumName ); + } else { + PRINTF( "%-4d (%-10s) ", EnumValue,"@$#%^&*"); + } + + } else { + // + // No auxilary information is associated with the ehumerated type + // print the numerical value. + // + PRINTF( "%-16d",EnumValue); + } + } + break; + + case FieldTypeStruct: + PRINTF( "@%-15X%s", + (dwAddress + pFieldDescriptors->Offset ), + NewLineForFields(i) ); + break; + + case FieldTypeLargeInteger: + case FieldTypeFileTime: + default: + ERROR( "Unrecognized field type %c for %s\n", pFieldDescriptors->FieldType, pFieldDescriptors->Name ); + break; + } + } +} + +LPSTR LibCommands[] = { + "dump <Struct Type Name>@<address expr> ", + "columns <d> -- controls the number of columns in the display ", + "logdump <Log Address> ", + 0 +}; + +BOOL +help( + DWORD dwCurrentPC, + PNTKD_EXTENSION_APIS lpExtensionApis, + LPSTR lpArgumentString +) +{ + int i; + + SETCALLBACKS(); + + for( i=0; Extensions[i]; i++ ) + PRINTF( " %s\n", Extensions[i] ); + + for( i=0; LibCommands[i]; i++ ) + PRINTF( " %s\n", LibCommands[i] ); + + return TRUE; +} + + +BOOL +columns( + DWORD dwCurrentPC, + PNTKD_EXTENSION_APIS lpExtensionApis, + LPSTR lpArgumentString +) +{ + ULONG NoOfColumns; + int i; + + SETCALLBACKS(); + + sscanf(lpArgumentString,"%ld",&NoOfColumns); + + if (NoOfColumns > s_MaxNoOfColumns) { + // PRINTF( "No. Of Columns exceeds maximum(%ld) -- directive Ignored\n", s_MaxNoOfColumns ); + } else { + s_NoOfColumns = NoOfColumns; + } + + PRINTF("Not Yet Implemented\n"); + + return TRUE; +} + + + +BOOL +globals( + DWORD dwCurrentPC, + PNTKD_EXTENSION_APIS lpExtensionApis, + LPSTR lpArgumentString +) +{ + DWORD dwAddress; + CHAR buf[ 100 ]; + int i; + int c=0; + + SETCALLBACKS(); + + strcpy( buf, "srv!" ); + + for( i=0; GlobalBool[i]; i++, c++ ) { + BOOL b; + + strcpy( &buf[4], GlobalBool[i] ); + dwAddress = (lpGetExpressionRoutine) ( buf ); + if( dwAddress == 0 ) { + ERROR( "Unable to get address of %s\n", GlobalBool[i] ); + continue; + } + if( !GetData( dwAddress,&b, sizeof(b)) ) + return FALSE; + + PRINTF( "%s%-30s %10s%s", + c&1 ? " " : "", + GlobalBool[i], + b ? " TRUE" : "FALSE", + c&1 ? "\n" : "" ); + } + + for( i=0; GlobalShort[i]; i++, c++ ) { + SHORT s; + + strcpy( &buf[4], GlobalShort[i] ); + dwAddress = (lpGetExpressionRoutine) ( buf ); + if( dwAddress == 0 ) { + ERROR( "Unable to get address of %s\n", GlobalShort[i] ); + continue; + } + if( !GetData( dwAddress,&s,sizeof(s)) ) + return FALSE; + + PRINTF( "%s%-30s %10d%s", + c&1 ? " " : "", + GlobalShort[i], + s, + c&1 ? "\n" : "" ); + } + + for( i=0; GlobalLong[i]; i++, c++ ) { + LONG l; + + strcpy( &buf[4], GlobalLong[i] ); + dwAddress = (lpGetExpressionRoutine) ( buf ); + if( dwAddress == 0 ) { + ERROR( "Unable to get address of %s\n", GlobalLong[i] ); + continue; + } + if( !GetData( dwAddress,&l, sizeof(l)) ) + return FALSE; + + PRINTF( "%s%-30s %10d%s", + c&1 ? " " : "", + GlobalLong[i], + l, + c&1 ? "\n" : "" ); + } + + PRINTF( "\n" ); + + return TRUE; +} + + +BOOL +version +( + DWORD dwCurrentPC, + PNTKD_EXTENSION_APIS lpExtensionApis, + LPSTR lpArgumentString +) +{ +#if VER_DEBUG + char *kind = "checked"; +#else + char *kind = "free"; +#endif + + SETCALLBACKS(); + + PRINTF( "Redirector debugger Extension dll for %s build %u\n", kind, VER_PRODUCTBUILD ); + + return TRUE; +} + +#define NAME_DELIMITER '@' +#define NAME_DELIMITERS "@" +#define INVALID_INDEX 0xffffffff +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + +ULONG SearchStructs(LPSTR lpArgument) +{ + ULONG i = 0; + STRUCT_DESCRIPTOR *pStructs = Structs; + ULONG NameIndex = INVALID_INDEX; + ULONG ArgumentLength = strlen(lpArgument); + BOOLEAN fAmbigous = FALSE; + + + while ((pStructs->StructName != 0)) { + int Result = _strnicmp(lpArgument, + pStructs->StructName, + MIN(strlen(pStructs->StructName),ArgumentLength)); + + if (Result == 0) { + if (NameIndex != INVALID_INDEX) { + // We have encountered duplicate matches. Print out the + // matching strings and let the user disambiguate. + fAmbigous = TRUE; + break; + } else { + NameIndex = i; + } + + } + pStructs++;i++; + } + + if (fAmbigous) { + PRINTF("Ambigous Name Specification -- The following structs match\n"); + PRINTF("%s\n",Structs[NameIndex].StructName); + PRINTF("%s\n",Structs[i].StructName); + while (pStructs->StructName != 0) { + if (_strnicmp(lpArgument, + pStructs->StructName, + MIN(strlen(pStructs->StructName),ArgumentLength)) == 0) { + PRINTF("%s\n",pStructs->StructName); + } + pStructs++; + } + PRINTF("Dumping Information for %s\n",Structs[NameIndex].StructName); + } + + return(NameIndex); +} + +VOID DisplayStructs() +{ + STRUCT_DESCRIPTOR *pStructs = Structs; + + PRINTF("The following structs are handled .... \n"); + while (pStructs->StructName != 0) { + PRINTF("\t%s\n",pStructs->StructName); + pStructs++; + } +} + +BOOL +dump( + DWORD dwCurrentPC, + PNTKD_EXTENSION_APIS lpExtensionApis, + LPSTR lpArgumentString +) +{ + DWORD dwAddress; + + SETCALLBACKS(); + + if( lpArgumentString && *lpArgumentString ) { + // Parse the argument string to determine the structure to be displayed. + // Scan for the NAME_DELIMITER ( '@' ). + + LPSTR lpName = lpArgumentString; + LPSTR lpArgs = strpbrk(lpArgumentString, NAME_DELIMITERS); + ULONG Index; + + if (lpArgs) { + // + // The specified command is of the form + // dump <name>@<address expr.> + // + // Locate the matching struct for the given name. In the case + // of ambiguity we seek user intervention for disambiguation. + // + // We do an inplace modification of the argument string to + // facilitate matching. + // + *lpArgs = '\0'; + + Index = SearchStructs(lpName); + + // + // Let us restore the original value back. + // + + *lpArgs = NAME_DELIMITER; + + if (INVALID_INDEX != Index) { + BYTE DataBuffer[512]; + + dwAddress = (lpGetExpressionRoutine)( ++lpArgs ); + if (GetData(dwAddress,DataBuffer,Structs[Index].StructSize)) { + + PRINTF( + "++++++++++++++++ %s@%lx ++++++++++++++++\n", + Structs[Index].StructName, + dwAddress); + PrintStructFields( + dwAddress, + &DataBuffer, + Structs[Index].FieldDescriptors); + PRINTF( + "---------------- %s@%lx ----------------\n", + Structs[Index].StructName, + dwAddress); + } else { + PRINTF("Error reading Memory @ %lx\n",dwAddress); + } + } else { + // No matching struct was found. Display the list of + // structs currently handled. + + DisplayStructs(); + } + } else { + // + // The command is of the form + // dump <name> + // + // Currently we do not handle this. In future we will map it to + // the name of a global variable and display it if required. + // + + DisplayStructs(); + } + } else { + // + // display the list of structs currently handled. + // + + DisplayStructs(); + } + + return TRUE; +} + +#if 0 +BOOL +logdump( + DWORD dwCurrentPC, + PNTKD_EXTENSION_APIS lpExtensionApis, + LPSTR lpArgumentString +) +{ + DWORD dwAddress; + BYTE DataBuffer[512]; + + SETCALLBACKS(); + + if( lpArgumentString && *lpArgumentString ) { + RX_LOG RxLog; + + dwAddress = (lpGetExpressionRoutine)(lpArgumentString); + if (GetData(dwAddress,&RxLog,sizeof(RX_LOG))) { + // Dump the log header followed by the log entries ... + ULONG dwCurEntry; + + PRINTF("s_RxLog.State %lx\n",RxLog.State); + PRINTF("s_RxLog.pHeadEntry %lx\n",RxLog.pHeadEntry); + PRINTF("s_RxLog.pTailEntry %lx\n",RxLog.pTailEntry); + PRINTF("s_RxLog.LogBufferSize %lx\n",RxLog.LogBufferSize); + PRINTF("s_RxLog.pLogBuffer %lx\n",RxLog.pLogBuffer); + PRINTF("s_RxLog.pWrapAroundPoint %lx\n",RxLog.pWrapAroundPoint); + PRINTF("s_RxLog.NumberOfEntriesIgnored %lx\n",RxLog.NumberOfEntriesIgnored); + PRINTF("s_RxLog.NumberOfLogWriteAttempts %lx\n",RxLog.NumberOfLogWriteAttempts); + + dwCurEntry = (DWORD)RxLog.pHeadEntry; + for (;;) { + PRX_LOG_ENTRY_HEADER pHeader; + ULONG LogRecordLength; + DWORD dwNextEntry; + + if (!GetData(dwCurEntry,DataBuffer,sizeof(RX_LOG_ENTRY_HEADER))) { + PRINTF("Error reading Memory @ %lx\n",dwAddress); + break; + } + + pHeader = (PRX_LOG_ENTRY_HEADER)DataBuffer; + LogRecordLength = pHeader->EntrySize - sizeof(RX_LOG_ENTRY_HEADER); + dwNextEntry = dwCurEntry + pHeader->EntrySize; + + if ((pHeader->EntrySize > 0) && + GetData((dwCurEntry + sizeof(RX_LOG_ENTRY_HEADER)), + DataBuffer, + LogRecordLength)) { + DataBuffer[LogRecordLength] = '\0'; + PRINTF("%s",DataBuffer); + } + + + if (RxLog.pTailEntry > RxLog.pHeadEntry) { + if (dwNextEntry > (DWORD)RxLog.pTailEntry) { + break; + } + } else { + if (dwNextEntry > (DWORD)RxLog.pHeadEntry) { + if ((dwNextEntry >= (DWORD)RxLog.pWrapAroundPoint) || + (dwNextEntry >= (DWORD)((PBYTE)RxLog.pLogBuffer + RxLog.LogBufferSize))) { + dwNextEntry = (DWORD)RxLog.pLogBuffer; + } + } else if (dwNextEntry > (DWORD)RxLog.pTailEntry) { + break; + } + } + + dwCurEntry = dwNextEntry; + } + } else { + PRINTF("Error reading Memory @ %lx\n",dwAddress); + } + } else { + PRINTF("usage: logdump <log address>\n"); + } + + return TRUE; +} +#endif + |