windows-nt/Source/XPSP1/NT/net/qos/psched/kdext/logger.c
2020-09-26 16:20:57 +08:00

814 lines
18 KiB
C

/*++
Copyright (c) 1992-1999 Microsoft Corporation
Module Name:
kdexts.c
Abstract:
This function contains some example KD debugger extensions
Author:
John Vert (jvert) 6-Aug-1992
Revision History:
--*/
#include "precomp.h"
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
// Forward function definitions
PCHAR
FindPreamble(
CHAR * BufferPointer,
BOOLEAN FirstTime
);
VOID
ParseBuffer(
CHAR * DataStart,
ULONG SkipCnt
);
PCHAR
ParseOidRecord(
CHAR * DataStart,
ULONG SkipCnt
);
PCHAR
ParseTimeRecord(
CHAR * DataStart,
ULONG SkipCnt
);
PCHAR
ParseStringRecord(
CHAR * DataStart,
ULONG SkipCnt
);
PCHAR
ParseSchedRecord(
CHAR * DataStart,
ULONG SkipCnt
);
PCHAR
ParseRecvRecord(
CHAR * DataStart,
ULONG SkipCnt
);
PCHAR
ParseSendRecord(
CHAR * DataStart,
ULONG SkipCnt
);
static PCHAR SchedModules[] = {
"NOP",
"TB CONFORMER",
"SHAPER",
"DRR SEQ",
"CBQ"};
static PCHAR SchedActions[] = {
"NOP",
"ENQUEUE",
"DEQUEUE",
"CONFORMANCE",
"DISCARD"};
static PCHAR SendRecvActions[] = {
"",
"ENTER",
"NO_RESOURCES",
"LOW_RESOURCES",
"INDICATING",
"RETURNED",
"NOT_OURS",
"OURS",
"RETURNING",
"TRANSFERRING",
"NOT READY"};
static PCHAR RecvEvents[] = {
"",
"CL_RECV_PACKET",
"MP_RETURN_PACKET",
"CL_RECV_INDICATION",
"CL_RECV_COMPLETE",
"MP_TRANSFER_DATA",
"CL_TRANSFER_COMPLETE"};
static PCHAR SendEvents[] = {
"",
"MP_SEND",
"MP_CO_SEND",
"DUP_PACKET",
"DROP_PACKET",
"CL_SEND_COMPLETE" };
//
// globals
//
CHAR Preamble[] = {(CHAR)0xef,(CHAR)0xbe,(CHAR)0xad,(CHAR)0xde};
ULONG ByteCheck = 0;
ULONG SafetyLimit;
BOOL
SafeRead(
DWORD offset,
LPVOID lpBuffer,
DWORD cb,
LPDWORD lpcbBytesRead
)
{
if(ByteCheck <= SafetyLimit){
ReadMemory(offset, lpBuffer, cb, lpcbBytesRead);
ByteCheck += cb;
return TRUE;
}
else{
dprintf("SafetyLimit of %d, exceeded, quitting!\n", SafetyLimit);
return FALSE;
}
}
DWORD
MyOpenFile (
IN PCHAR Name,
IN PWINDBG_OUTPUT_ROUTINE out,
OUT HANDLE *File
)
{
HANDLE hFile;
hFile = CreateFile(Name,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS ,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile) {
out ("MyOpenFile: CreateFile Failed.\n");
}
*File = hFile;
return(INVALID_HANDLE_VALUE == hFile ? (!(ERROR_SUCCESS)) : ERROR_SUCCESS);
}
VOID
MyWriteFile (
PCHAR buffer,
HANDLE file,
IN PWINDBG_OUTPUT_ROUTINE out
)
{
LONG len;
BOOL bRv;
DWORD dwWritten;
if (!buffer) {
out("MyWriteFile: Buffer is null\n");
}
len = strlen(buffer);
bRv = WriteFile( file, buffer, len, &dwWritten, NULL );
if (!bRv) {
out("WriteFile: Puked\n");
}
}
CHAR * BufferBase; // Start address of trace buffer, in host memory
CHAR * BufferEnd; // End address of trace buffer, in host memory
CHAR * BufferPointer; // Current location in host memory buffer
LONG BufferSize; // Total size of host memory buffer, in bytes.
LONG BufferCount; // Total count of traced bytes.
LONG TotalValidBytesRead = 0;
#define OUTPUT_ERROR 0
#define OUTPUT_FILE 1
#define OUTPUT_CONSOLE 2
CHAR FileIt;
HANDLE FileHandle;
ULONG LineNumber = 0;
DECLARE_API( tt )
{
DWORD hostAddress;
CHAR DeviceName[] = "c:\\tmp\\";
CHAR buffer[255];
DWORD status;
LONG pBufferBase;
LONG pBufferCount;
LONG pBufferSize;
BOOL success;
DWORD bytesread;
CHAR *s, *dataStart;
ULONG skip=0;
char SchedBufBase[] = {"&psched!SchedTraceBuffer"};
char SchedCount[] = {"&psched!SchedTraced"};
char BuffSize[] = {"&psched!SchedBufferSize"};
TotalValidBytesRead = 0;
LineNumber = 0;
FileIt = OUTPUT_ERROR;
if ( *args != '\0' ) {
// First argument is the file name.
s = strtok((LPSTR)args, " ");
strcpy( buffer, DeviceName );
strcat( buffer, s );
// next arg is the optional args.
while((s = strtok(NULL, " ")) != NULL)
{
if(s[0] == '-')
{
switch(s[1])
{
case 's':
case 'S':
skip = atoi(&s[2]);
break;
default:
dprintf("Usage: !tt [filename] [-S<#>] \n");
dprintf(" S : No of records (from head) to skip \n");
goto cleanup;
}
}
}
status = MyOpenFile( buffer, dprintf, &FileHandle );
if ( status == ERROR_SUCCESS ) {
FileIt = OUTPUT_FILE;
}
else {
goto cleanup;
}
dprintf( "handle =%x status=%x FileIt=%d\n", FileHandle, status, FileIt );
}
else {
FileIt = OUTPUT_CONSOLE;
}
hostAddress = GetExpression(SchedBufBase);
pBufferBase = (LONG)hostAddress;
if (!pBufferBase){
dprintf("bad string conversion (%s) \n", SchedBufBase);
goto cleanup;
}
hostAddress = GetExpression(SchedCount);
pBufferCount = hostAddress;
if (!pBufferCount) {
dprintf( " bad string conversion (%s) \n", SchedCount );
goto cleanup;
}
hostAddress = GetExpression(BuffSize);
pBufferSize = hostAddress;
if (!pBufferSize) {
dprintf( " bad string conversion (%s) \n", SchedCount );
goto cleanup;
}
success = ReadMemory((ULONG)pBufferCount, &BufferCount, sizeof(LONG), &bytesread );
if (!success){
dprintf("problems reading memory at %x for %x bytes\n", pBufferCount, sizeof(LONG));
goto cleanup;
}
success = ReadMemory((ULONG)pBufferSize, &BufferSize, sizeof(LONG), &bytesread );
if (!success){
dprintf("problems reading memory at %x for %x bytes\n", pBufferSize, sizeof(LONG));
goto cleanup;
}
success = ReadMemory((ULONG)pBufferBase, &BufferBase, sizeof(LONG), &bytesread );
if (!success){
dprintf("problems reading memory at %x for %x bytes\n", pBufferBase, sizeof(LONG));
goto cleanup;
}
SafetyLimit = (ULONG)-1;
if(!BufferCount){
dprintf("No data in buffer.\n");
goto cleanup;
}
dprintf("struct@%x, total bytes traced: %d, buffer size: %d\n", BufferBase, BufferCount, BufferSize);
// Find the starting point. If we haven't wrapped the buffer, it's at BufferBase.
// If we have wrapped the buffer, we start right after our current pointer.
// In either case, BufferPointer is the host address at which we should
// start looking for data.
if(BufferCount <= BufferSize){
BufferPointer = BufferBase;
}
else{
BufferPointer = BufferBase + (BufferCount % BufferSize);
}
BufferEnd = BufferBase + BufferSize;
// dataStart will point to the first location after the
// first preamble (in host memory), or - will be zero,
// indicating that no preamble was found.
dataStart = FindPreamble(BufferPointer, TRUE);
if(dataStart){
ParseBuffer(dataStart, skip);
}
else{
dprintf("Error reading token trace buffer. Could not find preamble.\n");
}
cleanup:
if(FileIt == OUTPUT_FILE){
CloseHandle( FileHandle );
}
}
PCHAR
FindPreamble(
CHAR * BufferPointer,
BOOLEAN FirstTime
)
{
LONG count;
LONG i;
CHAR * readFrom;
CHAR hold;
BOOL success;
DWORD bytesread;
count = 0;
i = 0;
readFrom = BufferPointer;
while(TRUE){
success = SafeRead((ULONG)readFrom, &hold, 1, &bytesread );
if (!success){
dprintf("problems reading memory at %x for %x bytes\n", readFrom, 1);
break;
}
if(hold == Preamble[i]){
i++;
}
else{
i=0;
}
if(i == sizeof(TRACE_PREAMBLE)){
if(FirstTime){
dprintf("Found start of first record at %d.\n", readFrom+1 - BufferBase);
}
TotalValidBytesRead += sizeof(TRACE_PREAMBLE);
readFrom++;
break;
}
readFrom++;
if(readFrom > BufferEnd){
readFrom = BufferBase;
}
count++;
if(count == TRACE_BUFFER_SIZE){
readFrom = 0;
break;
}
}
return(readFrom);
}
VOID
ParseBuffer(
CHAR * DataStart,
ULONG SkipCnt
)
{
CHAR * dataStart;
CHAR * recordEnd;
LONG records;
BOOL success;
CHAR hold;
DWORD bytesread;
records = 0;
dataStart = DataStart;
while(TRUE){
success = SafeRead((ULONG)dataStart, &hold, 1, &bytesread );
if (!success){
dprintf("problems reading memory at %x for %x bytes\n", dataStart, 1);
break;
}
switch(hold){
case RECORD_TSTRING:
recordEnd = ParseStringRecord(dataStart, SkipCnt);
break;
case RECORD_OID:
recordEnd = ParseOidRecord(dataStart, SkipCnt);
break;
case RECORD_SCHED:
recordEnd = ParseSchedRecord(dataStart, SkipCnt);
break;
case RECORD_RECV:
recordEnd = ParseRecvRecord(dataStart, SkipCnt);
break;
case RECORD_SEND:
recordEnd = ParseSendRecord(dataStart, SkipCnt);
break;
default:
dprintf("Unrecognized record type!\n");
}
records++;
if(TotalValidBytesRead >= BufferCount){
dprintf("\nCompleted parsing trace buffer. %d records found.\n", records);
break;
}
dataStart = FindPreamble(recordEnd, FALSE);
if(dataStart == DataStart){
dprintf("\nCompleted parsing trace buffer. %d records found.\n", records);
break;
}
}
}
VOID
GetBytesToRead(
CHAR * DataStart,
LONG RecordSize,
LONG * BytesToReadFirst,
LONG * BytesToReadNext
)
{
if((DataStart + RecordSize - sizeof(TRACE_PREAMBLE)) > BufferEnd){
*BytesToReadFirst = BufferEnd - DataStart;
*BytesToReadNext = RecordSize - sizeof(TRACE_PREAMBLE) - *BytesToReadFirst;
}
else{
*BytesToReadFirst = RecordSize - sizeof(TRACE_PREAMBLE);
*BytesToReadNext = 0;
}
}
PCHAR
ParseAnyRecord(
CHAR * DataStart,
CHAR * Record,
LONG RecordSize
)
{
LONG bytesToReadFirst;
LONG bytesToReadNext;
BOOL success;
CHAR * nextDataStart;
DWORD bytesread;
CHAR * pRecordData;
CHAR buffer[255];
GetBytesToRead(DataStart, RecordSize, &bytesToReadFirst, &bytesToReadNext);
pRecordData = Record + sizeof(TRACE_PREAMBLE);
success = SafeRead((ULONG)DataStart, pRecordData, bytesToReadFirst, &bytesread );
TotalValidBytesRead += bytesToReadFirst;
if (!success){
dprintf("problems reading memory at %x for %x bytes\n", DataStart, 1);
}
nextDataStart = DataStart + bytesToReadFirst;
if(bytesToReadNext){
success = SafeRead((ULONG)BufferBase,
pRecordData + bytesToReadFirst,
bytesToReadNext,
&bytesread);
TotalValidBytesRead += bytesToReadNext;
if (!success){
dprintf("problems reading memory at %x for %x bytes\n", BufferBase, 1);
}
nextDataStart = BufferBase + bytesToReadNext;
}
return(nextDataStart);
}
PCHAR
ParseOidRecord(
CHAR * DataStart,
ULONG SkipCnt
)
{
TRACE_RECORD_OID record;
CHAR buffer[255];
CHAR * nextDataStart;
static PCHAR OIDActions[] =
{
"",
"MpSetInformation",
"MpQueryInformation",
"SetRequestComplete",
"QueryRequestComplete"
};
nextDataStart = ParseAnyRecord(DataStart, (CHAR *)&record, sizeof(TRACE_RECORD_OID));
if(++LineNumber < SkipCnt)
return nextDataStart;
if(record.Now.QuadPart){
wsprintf(buffer, "[%4d]:[%u.%u]: OID: %5s:%9s:%08X:%08X:%08X \n",
LineNumber,
record.Now.HighPart,
record.Now.LowPart,
OIDActions[record.Action],
record.Local == TRUE?"Local":"Non Local",
record.Adapter,
record.Oid,
record.Status);
}
else {
wsprintf(buffer, "[%4d]: OID: %5s:%9s:%08X:%08X:%08X \n",
LineNumber,
OIDActions[record.Action],
record.Local == TRUE?"Local":"Non Local",
record.Adapter,
record.Oid,
record.Status);
}
switch(FileIt)
{
case OUTPUT_FILE:
MyWriteFile(buffer, FileHandle, dprintf);
break;
case OUTPUT_CONSOLE:
dprintf(buffer);
break;
default:
dprintf("Failed to create file! Check for tmp directory.\n");
break;
}
return(nextDataStart);
}
PCHAR
ParseStringRecord(
CHAR * DataStart,
ULONG SkipCnt
)
{
TRACE_RECORD_STRING record;
LONG bytesToReadFirst;
LONG bytesToReadNext;
BOOL success;
CHAR * nextDataStart;
DWORD bytesread;
CHAR * pRecordData;
CHAR buffer[255];
nextDataStart = ParseAnyRecord(DataStart, (CHAR *)&record, sizeof(TRACE_RECORD_STRING));
if(++LineNumber < SkipCnt)
return nextDataStart;
if(record.Now.QuadPart){
wsprintf(buffer, "[%4d]:[%u.%u]:%s",
LineNumber,
record.Now.HighPart,
record.Now.LowPart,
record.StringStart);
}
else{
wsprintf(buffer, "[%4d]:%s",
LineNumber,
record.StringStart);
}
switch(FileIt)
{
case OUTPUT_FILE:
MyWriteFile(buffer, FileHandle, dprintf);
break;
case OUTPUT_CONSOLE:
dprintf(buffer);
break;
default:
dprintf("Failed to create file! Check for tmp directory.\n");
break;
}
return(nextDataStart);
}
PCHAR
ParseSchedRecord(
CHAR * DataStart,
ULONG SkipCnt
)
{
TRACE_RECORD_SCHED record;
LONG bytesToReadFirst;
LONG bytesToReadNext;
BOOL success;
CHAR * nextDataStart;
DWORD bytesread;
CHAR * pRecordData;
ULONG now;
CHAR buffer[255];
LARGE_INTEGER ConformanceTime;
nextDataStart = ParseAnyRecord(DataStart, (CHAR *)&record, sizeof(TRACE_RECORD_SCHED));
if(++LineNumber < SkipCnt)
return nextDataStart;
ConformanceTime.QuadPart = record.ConformanceTime;
wsprintf(buffer,
"[%4d]:[%u.%u]:%s:VC %x:%x:%u:%s:%d:%d:%u:%u\n",
LineNumber,
record.Now.HighPart,
record.Now.LowPart,
SchedModules[record.SchedulerComponent],
record.VC,
record.Packet,
record.PacketLength,
SchedActions[record.Action],
record.Priority,
ConformanceTime.HighPart,
ConformanceTime.LowPart,
record.PacketsInComponent);
switch(FileIt)
{
case OUTPUT_FILE:
MyWriteFile(buffer, FileHandle, dprintf);
break;
case OUTPUT_CONSOLE:
dprintf(buffer);
break;
default:
dprintf("Failed to create file! Check for tmp directory.\n");
break;
}
return(nextDataStart);
}
PCHAR
ParseRecvRecord(
CHAR * DataStart,
ULONG SkipCnt
)
{
TRACE_RECORD_RECV record;
LONG bytesToReadFirst;
LONG bytesToReadNext;
BOOL success;
CHAR * nextDataStart;
DWORD bytesread;
CHAR * pRecordData;
CHAR buffer[255];
nextDataStart = ParseAnyRecord(DataStart, (CHAR *)&record,
sizeof(TRACE_RECORD_RECV));
if(++LineNumber < SkipCnt)
return nextDataStart;
wsprintf(buffer,
"[%4d]:[%u.%u]:Adapter %08X:%s:%s:%x:%x \n",
LineNumber,
record.Now.HighPart,
record.Now.LowPart,
record.Adapter,
RecvEvents[record.Event],
SendRecvActions[record.Action],
record.Packet1,
record.Packet2);
switch(FileIt)
{
case OUTPUT_FILE:
MyWriteFile(buffer, FileHandle, dprintf);
break;
case OUTPUT_CONSOLE:
dprintf(buffer);
break;
default:
dprintf("Failed to create file! Check for tmp directory.\n");
break;
}
return(nextDataStart);
}
PCHAR
ParseSendRecord(
CHAR * DataStart,
ULONG SkipCnt
)
{
TRACE_RECORD_SEND record;
LONG bytesToReadFirst;
LONG bytesToReadNext;
BOOL success;
CHAR * nextDataStart;
DWORD bytesread;
CHAR * pRecordData;
CHAR buffer[255];
nextDataStart = ParseAnyRecord(DataStart, (CHAR *)&record,
sizeof(TRACE_RECORD_SEND));
if(++LineNumber < SkipCnt)
return nextDataStart;
wsprintf(buffer,
"[%4d]:[%u.%u]:Adapter %08X:%s:%s:%x:%x:%x\n",
LineNumber,
record.Now.HighPart,
record.Now.LowPart,
record.Adapter,
SendEvents[record.Event],
SendRecvActions[record.Action],
record.Vc,
record.Packet1,
record.Packet2);
switch(FileIt)
{
case OUTPUT_FILE:
MyWriteFile(buffer, FileHandle, dprintf);
break;
case OUTPUT_CONSOLE:
dprintf(buffer);
break;
default:
dprintf("Failed to create file! Check for tmp directory.\n");
break;
}
return(nextDataStart);
}