Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

3768 lines
100 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
api.c
Abstract:
This module implements the all apis that simulate their
WIN32 counterparts.
Author:
Wesley Witt (wesw) 8-Mar-1992
Environment:
NT 3.1
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// structures & defines for queue management
//
typedef struct tagCQUEUE {
struct tagCQUEUE *next;
DWORD pid;
DWORD tid;
DWORD typ;
DWORD len;
DWORD data;
} CQUEUE, *LPCQUEUE;
LPCQUEUE lpcqFirst;
LPCQUEUE lpcqLast;
LPCQUEUE lpcqFree;
CQUEUE cqueue[200];
CRITICAL_SECTION csContinueQueue;
//
// context cache
//
typedef struct _tagCONTEXTCACHE {
CONTEXT Context;
#if defined(TARGET_i386) || defined(TARGET_PPC)
KSPECIAL_REGISTERS sregs;
BOOL fSContextStale;
BOOL fSContextDirty;
#endif // i386 || PPC
BOOL fContextStale;
BOOL fContextDirty;
} CONTEXTCACHE, *LPCONTEXTCACHE;
CONTEXTCACHE ContextCache[MAXIMUM_PROCESSORS];
DWORD CacheProcessors = 1; // up machine by default
#if defined(TARGET_MIPS)
MIPSCONTEXTSIZE MipsContextSize;
#endif
extern MODULEALIAS ModuleAlias[];
//
// globals
//
DWORD DmKdState = S_UNINITIALIZED;
BOOL DmKdExit;
DBGKD_WAIT_STATE_CHANGE sc;
BOOL fScDirty;
BOOL ApiIsAllowed;
HANDLE hEventContinue;
BOOL fCrashDump;
DBGKD_WRITE_BREAKPOINT bps[64];
BOOL bpcheck[64];
HANDLE hThreadDmPoll;
DBGKD_GET_VERSION vs;
PDUMP_HEADER DmpHeader;
char szProgName[MAX_PATH];
DWORD PollThreadId;
PKPRCB KiProcessors[MAXIMUM_PROCESSORS];
PCONTEXT DmpContext;
BOOL fPacketTrace;
//
// kernel symbol addresses
//
ULONG DcbAddr;
ULONG MmLoadedUserImageList;
ULONG KiPcrBaseAddress;
ULONG KiProcessorBlockAddr;
#define IsApiAllowed() if (!ApiIsAllowed) return 0;
#define NoApiForCrashDump() if (fCrashDump) return 0;
#define ConsumeAllEvents() DequeueAllEvents(FALSE,TRUE)
#define END_OF_CONTROL_SPACE (sizeof(KPROCESSOR_STATE))
#define CRASH_BUGCHECK_CODE 0xDEADDEAD
//
// local prototypes
//
BOOL GenerateKernelModLoad(HPRCX hprc, LPSTR lpProgName);
//
// externs
//
extern jmp_buf JumpBuffer;
extern BOOL DmKdBreakIn;
extern BOOL KdResync;
extern BOOL InitialBreak;
extern HANDLE hEventCreateProcess;
extern HANDLE hEventCreateThread;
extern HANDLE hEventRemoteQuit;
extern HANDLE hEventContinue;
extern HPRCX prcList;
extern BOOL fDisconnected;
extern LPDM_MSG LpDmMsg;
extern PKILLSTRUCT KillQueue;
extern CRITICAL_SECTION csKillQueue;
extern HTHDX thdList;
extern HPRCX prcList;
extern CRITICAL_SECTION csThreadProcList;
extern BOOL fSmartRangeStep;
extern HANDLE hEventNoDebuggee;
extern HANDLE hEventRemoteQuit;
extern BOOL fDisconnected;
extern BOOL fUseRoot;
extern char nameBuffer[];
DWORD GetSymbolAddress( LPSTR sym );
BOOL UnloadModule( DWORD BaseOfDll, LPSTR NameOfDll );
VOID UnloadAllModules( VOID );
VOID DisableEmCache( VOID );
VOID InitializeKiProcessor(VOID);
VOID ProcessCacheCmd(LPSTR pchCommand);
BOOL
DbgReadMemory(
HPRCX hprc,
PVOID lpBaseAddress,
PVOID lpBuffer,
DWORD nSize,
PDWORD lpcbRead
)
{
DWORD cb;
int iDll;
int iobj;
static PIMAGE_SECTION_HEADER s = NULL;
BOOL non_discardable = FALSE;
PDLLLOAD_ITEM d;
IsApiAllowed();
if (nSize == 0) {
return TRUE;
}
//
// the following code is necessary to determine if the requested
// base address is in a read-only page or is in a page that contains
// code. if the base address meets these conditions then is is marked
// as non-discardable and will never be purged from the cache.
//
if (s &&
(DWORD)lpBaseAddress >= s->VirtualAddress &&
(DWORD)lpBaseAddress < s->VirtualAddress+s->SizeOfRawData &&
((s->Characteristics & IMAGE_SCN_CNT_CODE) ||
(!s->Characteristics & IMAGE_SCN_MEM_WRITE))) {
non_discardable = TRUE;
}
else {
d = prcList->next->rgDllList;
for (iDll=0; iDll<prcList->next->cDllList; iDll++) {
if ((DWORD)lpBaseAddress >= d[iDll].offBaseOfImage &&
(DWORD)lpBaseAddress < d[iDll].offBaseOfImage+d[iDll].cbImage) {
if (!d[iDll].Sections) {
if (d[iDll].sec) {
d[iDll].Sections = d[iDll].sec;
for (iobj=0; iobj<(int)d[iDll].NumberOfSections; iobj++) {
d[iDll].Sections[iobj].VirtualAddress += (DWORD)d[iDll].offBaseOfImage;
}
}
}
s = d[iDll].Sections;
cb = d[iDll].NumberOfSections;
while (cb) {
if ((DWORD)lpBaseAddress >= s->VirtualAddress &&
(DWORD)lpBaseAddress < s->VirtualAddress+s->SizeOfRawData &&
((s->Characteristics & IMAGE_SCN_CNT_CODE) ||
(!s->Characteristics & IMAGE_SCN_MEM_WRITE))) {
non_discardable = TRUE;
break;
}
else {
s++;
cb--;
}
}
if (!cb) {
s = NULL;
}
break;
}
}
}
if (fCrashDump) {
cb = DmpReadMemory( lpBaseAddress, lpBuffer, nSize );
} else {
if (DmKdReadCachedVirtualMemory( (DWORD) lpBaseAddress,
nSize,
(PUCHAR) lpBuffer,
&cb,
non_discardable) != STATUS_SUCCESS ) {
cb = 0;
}
}
if ( cb > 0 && non_discardable ) {
BREAKPOINT *bp;
ADDR Addr;
BP_UNIT instr;
DWORD offset;
LPVOID lpb;
AddrInit( &Addr, 0, 0, (UOFF32)lpBaseAddress, TRUE, TRUE, FALSE, FALSE );
lpb = lpBuffer;
for (bp=bpList->next; bp; bp=bp->next) {
if (BPInRange((HPRCX)0, (HTHDX)0, bp, &Addr, cb, &offset, &instr)) {
if (instr) {
if (offset < 0) {
memcpy(lpb, ((char *) &instr) - offset,
sizeof(BP_UNIT) + offset);
} else if (offset + sizeof(BP_UNIT) > cb) {
memcpy(((char *)lpb)+offset, &instr, cb - offset);
} else {
*((BP_UNIT UNALIGNED *)((char *)lpb+offset)) = instr;
}
}
}
}
}
if (cb > 0) {
if (lpcbRead) {
*lpcbRead = cb;
}
return TRUE;
} else {
return FALSE;
}
}
BOOL
DbgWriteMemory(
HPRCX hprc,
PVOID lpBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpcbWrite
)
{
ULONG cb;
IsApiAllowed();
if (nSize == 0) {
return TRUE;
}
if (fCrashDump) {
cb = DmpWriteMemory( lpBaseAddress, lpBuffer, nSize );
} else {
if (DmKdWriteVirtualMemory( lpBaseAddress,
lpBuffer,
nSize,
&cb ) != STATUS_SUCCESS ) {
cb = 0;
}
}
if (cb > 0) {
if (lpcbWrite) {
*lpcbWrite = cb;
}
return TRUE;
} else {
return FALSE;
}
}
BOOL
DbgGetThreadContext(
IN HTHDX hthd,
OUT LPCONTEXT lpContext
)
{
BOOL rc = TRUE;
USHORT processor;
DWORD Flags = lpContext->ContextFlags;
DPRINT(1, ( "DbgGetThreadContext( 0x%x )\n", lpContext ));
IsApiAllowed();
if (!hthd) {
return FALSE;
}
processor = (USHORT)hthd->tid - 1;
if (fCrashDump) {
if (processor == sc.Processor && KiProcessors[processor] == 0) {
memcpy( lpContext, DmpContext, sizeof(CONTEXT) );
rc = TRUE;
} else {
rc = DmpGetContext( processor, lpContext );
#if defined(TARGET_MIPS)
if (rc) {
if (DmpHeader->MajorVersion > 3) {
MipsContextSize = Ctx64Bit;
} else {
MipsContextSize = Ctx32Bit;
CoerceContext32To64(&ContextCache[processor].Context);
}
}
#endif
}
} else {
if (ContextCache[processor].fContextStale) {
rc = (DmKdGetContext( processor, &ContextCache[processor].Context )
== STATUS_SUCCESS);
if (rc) {
ContextCache[processor].fContextDirty = FALSE;
ContextCache[processor].fContextStale = FALSE;
#if defined(TARGET_MIPS)
if ((ContextCache[processor].Context.ContextFlags &
CONTEXT_EXTENDED_INTEGER) == CONTEXT_EXTENDED_INTEGER) {
MipsContextSize = Ctx64Bit;
} else {
MipsContextSize = Ctx32Bit;
CoerceContext32To64(&ContextCache[processor].Context);
}
#endif
}
}
if (rc) {
memcpy( lpContext,
&ContextCache[processor].Context,
sizeof(ContextCache[processor].Context) );
}
}
#if defined(TARGET_MIPS)
if (rc) {
if ((Flags & CONTEXT_EXTENDED_INTEGER) == CONTEXT_EXTENDED_INTEGER) {
CoerceContext32To64(lpContext);
} else if ((Flags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
CoerceContext64To32(lpContext);
}
}
#endif
if (rc) {
hthd->fContextStale = FALSE;
}
return rc;
}
BOOL
DbgSetThreadContext(
IN HTHDX hthd,
IN LPCONTEXT lpContext
)
{
BOOL rc = TRUE;
USHORT processor;
#if defined(TARGET_MIPS)
CONTEXT LocalContext;
#endif
DEBUG_PRINT_1( "DbgSetThreadContext( 0x%x )\n", lpContext );
IsApiAllowed();
NoApiForCrashDump();
processor = (USHORT)hthd->tid - 1;
memcpy( &ContextCache[processor].Context, lpContext, sizeof(CONTEXT) );
#if defined(TARGET_MIPS)
CoerceContext32To64( &ContextCache[processor].Context );
#endif
if (lpContext != &hthd->context) {
memcpy(&hthd->context, &ContextCache[processor].Context, sizeof(CONTEXT));
}
ContextCache[processor].fContextDirty = FALSE;
ContextCache[processor].fContextStale = FALSE;
#if defined(TARGET_MIPS)
if (MipsContextSize == Ctx64Bit) {
lpContext = &ContextCache[processor].Context;
} else {
memcpy( &LocalContext, lpContext, sizeof(CONTEXT) );
CoerceContext32To64( &LocalContext );
lpContext = &LocalContext;
}
#endif
if (DmKdSetContext( processor, lpContext ) != STATUS_SUCCESS) {
rc = FALSE;
}
return rc;
}
BOOL
WriteBreakPoint(
IN PBREAKPOINT Breakpoint
)
{
BOOL rc = TRUE;
DEBUG_PRINT_2( "WriteBreakPoint( 0x%08x, 0x%08x )\n",
GetAddrOff(Breakpoint->addr),
Breakpoint->hBreakPoint);
IsApiAllowed();
NoApiForCrashDump();
if (DmKdWriteBreakPoint( (PVOID)GetAddrOff(Breakpoint->addr),
&Breakpoint->hBreakPoint ) != STATUS_SUCCESS) {
rc = FALSE;
}
return rc;
}
BOOL
WriteBreakPointEx(
IN HTHDX hthd,
IN ULONG BreakPointCount,
IN OUT PDBGKD_WRITE_BREAKPOINT BreakPoints,
IN ULONG ContinueStatus
)
{
BOOL rc = TRUE;
assert( BreakPointCount > 0 );
assert( BreakPoints );
DEBUG_PRINT_2( "WriteBreakPointEx( %d, 0x%08x )\n",
BreakPointCount, BreakPoints );
IsApiAllowed();
NoApiForCrashDump();
if (DmKdWriteBreakPointEx( BreakPointCount, BreakPoints, ContinueStatus ) != STATUS_SUCCESS) {
rc = FALSE;
}
return rc;
}
BOOL
RestoreBreakPoint(
IN PBREAKPOINT Breakpoint
)
{
BOOL rc = TRUE;
DEBUG_PRINT_1( "RestoreBreakPoint( 0x%08x )\n", Breakpoint->hBreakPoint );
IsApiAllowed();
NoApiForCrashDump();
if (DmKdRestoreBreakPoint( Breakpoint->hBreakPoint ) != STATUS_SUCCESS) {
rc = FALSE;
}
return rc;
}
BOOL
RestoreBreakPointEx(
IN ULONG BreakPointCount,
IN PDBGKD_RESTORE_BREAKPOINT BreakPointHandles
)
{
BOOL rc = TRUE;
assert( BreakPointCount > 0 );
assert( BreakPointHandles );
DEBUG_PRINT_2( "WriteBreakPointEx( %d, 0x%08x )\n",
BreakPointCount, BreakPointHandles );
IsApiAllowed();
NoApiForCrashDump();
if (DmKdRestoreBreakPointEx( BreakPointCount, BreakPointHandles ) != STATUS_SUCCESS) {
rc = FALSE;
}
return rc;
}
BOOL
ReadControlSpace(
USHORT Processor,
PVOID TargetBaseAddress,
PVOID UserInterfaceBuffer,
ULONG TransferCount,
PULONG ActualBytesRead
)
{
DWORD Status;
IsApiAllowed();
if (fCrashDump) {
return DmpReadControlSpace(
Processor,
TargetBaseAddress,
UserInterfaceBuffer,
TransferCount,
ActualBytesRead
);
}
Status = DmKdReadControlSpace(
Processor,
TargetBaseAddress,
UserInterfaceBuffer,
TransferCount,
ActualBytesRead
);
if (Status || (ActualBytesRead && *ActualBytesRead != TransferCount)) {
return FALSE;
}
return TRUE;
}
VOID
ContinueTargetSystem(
DWORD ContinueStatus,
PDBGKD_CONTROL_SET ControlSet
)
{
DWORD rc;
ApiIsAllowed = FALSE;
if (ControlSet) {
rc = DmKdContinue2( ContinueStatus, ControlSet );
} else {
rc = DmKdContinue( ContinueStatus );
}
}
ULONG
UnicodeStringToAnsiString(
PANSI_STRING DestinationString,
PUNICODE_STRING SourceString,
BOOLEAN AllocateDestinationString
)
{
if (AllocateDestinationString) {
DestinationString->Buffer = malloc( DestinationString->MaximumLength );
if (!DestinationString->Buffer) {
return 1;
}
}
DestinationString->Length = WideCharToMultiByte(
CP_ACP,
WC_COMPOSITECHECK,
SourceString->Buffer,
SourceString->Length / 2,
DestinationString->Buffer,
DestinationString->MaximumLength,
NULL,
NULL
);
return 0;
}
VOID
InitUnicodeString(
PUNICODE_STRING DestinationString,
PCWSTR SourceString
)
{
wcsncpy( DestinationString->Buffer, SourceString, DestinationString->MaximumLength );
DestinationString->Length = wcslen( DestinationString->Buffer ) * 2;
}
BOOL
ReloadModule(
HTHDX hthd,
PLDR_DATA_TABLE_ENTRY DataTableBuffer,
BOOL fDontUseLoadAddr,
BOOL fLocalBuffer
)
{
UNICODE_STRING BaseName;
CHAR AnsiBuffer[512];
WCHAR UnicodeBuffer[512];
ANSI_STRING AnsiString;
NTSTATUS Status;
DEBUG_EVENT de;
CHAR fname[_MAX_FNAME];
CHAR ext[_MAX_EXT];
ULONG cb;
//
// Get the base DLL name.
//
if (DataTableBuffer->BaseDllName.Length != 0 &&
DataTableBuffer->BaseDllName.Buffer != NULL ) {
BaseName = DataTableBuffer->BaseDllName;
} else
if (DataTableBuffer->FullDllName.Length != 0 &&
DataTableBuffer->FullDllName.Buffer != NULL ) {
BaseName = DataTableBuffer->FullDllName;
} else {
return FALSE;
}
if (BaseName.Length > sizeof(UnicodeBuffer)) {
DMPrintShellMsg( "cannot complete modload %08x\n", BaseName.Length );
return FALSE;
}
if (!fLocalBuffer) {
if (!DbgReadMemory( hthd->hprc, (PVOID)BaseName.Buffer, (PVOID)UnicodeBuffer, BaseName.Length, &cb )) {
return FALSE;
}
BaseName.Buffer = UnicodeBuffer;
BaseName.Length = (USHORT)cb;
BaseName.MaximumLength = (USHORT)(cb + sizeof( UNICODE_NULL ));
UnicodeBuffer[ cb / sizeof( WCHAR ) ] = UNICODE_NULL;
}
AnsiString.Buffer = AnsiBuffer;
AnsiString.MaximumLength = 256;
Status = UnicodeStringToAnsiString(&AnsiString, &BaseName, FALSE);
if (!NT_SUCCESS(Status)) {
return FALSE;
}
AnsiString.Buffer[AnsiString.Length] = '\0';
_splitpath( AnsiString.Buffer, NULL, NULL, fname, ext );
_makepath( AnsiString.Buffer, NULL, NULL, fname, ext );
de.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.LoadDll.hFile = (HANDLE)DataTableBuffer->CheckSum;
de.u.LoadDll.lpBaseOfDll = fDontUseLoadAddr ? 0 : (LPVOID) DataTableBuffer->DllBase;
de.u.LoadDll.lpImageName = AnsiString.Buffer;
de.u.LoadDll.dwDebugInfoFileOffset = DataTableBuffer->SizeOfImage;
de.u.LoadDll.fUnicode = FALSE;
de.u.LoadDll.nDebugInfoSize = 0;
NotifyEM(&de, hthd, 0, (LPVOID)0);
return TRUE;
}
BOOL
ReloadModulesFromList(
HTHDX hthd,
DWORD ListAddr,
BOOL fDontUseLoadAddr,
LPSTR JustLoadThisOne,
ULONG UseThisAddress
)
{
LIST_ENTRY List;
PLIST_ENTRY Next;
ULONG len = 0;
PLDR_DATA_TABLE_ENTRY DataTable;
LDR_DATA_TABLE_ENTRY DataTableBuffer;
WCHAR UnicodeBuffer[_MAX_PATH];
WCHAR UnicodeBuffer2[_MAX_PATH];
int Len;
BOOL LoadedSomething;
if (!ListAddr) {
return FALSE;
}
//
// convert the module name to unicode
//
*UnicodeBuffer = 0;
if (JustLoadThisOne) {
Len = strlen(JustLoadThisOne);
MultiByteToWideChar(
CP_OEMCP,
0,
JustLoadThisOne,
Len,
UnicodeBuffer,
sizeof(UnicodeBuffer)
);
}
if (!DbgReadMemory( hthd->hprc, (PVOID)ListAddr, (PVOID)&List, sizeof(LIST_ENTRY), NULL)) {
return FALSE;
}
Next = List.Flink;
if (Next == NULL) {
return FALSE;
}
LoadedSomething = FALSE;
while ((ULONG)Next != ListAddr) {
DataTable = CONTAINING_RECORD( Next,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks
);
if (!DbgReadMemory( hthd->hprc, (PVOID)DataTable, (PVOID)&DataTableBuffer, sizeof(LDR_DATA_TABLE_ENTRY), NULL)) {
break;
}
Next = DataTableBuffer.InLoadOrderLinks.Flink;
if (!JustLoadThisOne) {
ReloadModule( hthd, &DataTableBuffer, fDontUseLoadAddr, FALSE );
LoadedSomething = TRUE;
} else {
if (2*Len == DataTableBuffer.BaseDllName.Length) {
if (!DbgReadMemory( hthd->hprc,
(PVOID)DataTableBuffer.BaseDllName.Buffer,
(PVOID)UnicodeBuffer2,
DataTableBuffer.BaseDllName.Length,
NULL )) {
continue;
}
if (_wcsnicmp(UnicodeBuffer, UnicodeBuffer2, Len) == 0) {
if (UseThisAddress) {
DataTableBuffer.DllBase = (PVOID)UseThisAddress;
}
ReloadModule( hthd, &DataTableBuffer, fDontUseLoadAddr, FALSE );
LoadedSomething = TRUE;
break;
}
}
}
}
return LoadedSomething;
}
BOOL
ReloadCrashModules(
HTHDX hthd
)
{
ULONG ListAddr;
ULONG DcbPtr;
ULONG i;
DUMP_CONTROL_BLOCK dcb;
PLIST_ENTRY Next;
ULONG len = 0;
PMINIPORT_NODE mpNode;
MINIPORT_NODE mpNodeBuf;
PLDR_DATA_TABLE_ENTRY DataTable;
LDR_DATA_TABLE_ENTRY DataTableBuffer;
CHAR AnsiBuffer[512];
WCHAR UnicodeBuffer[512];
if (!DcbAddr) {
//
// kernel symbols are hosed
//
return FALSE;
}
if (!DbgReadMemory( hthd->hprc, (PVOID)DcbAddr, (PVOID)&DcbPtr, sizeof(DWORD), NULL)) {
return FALSE;
}
if (!DcbPtr) {
//
// crash dumps are not enabled
//
return FALSE;
}
if (!DbgReadMemory( hthd->hprc, (PVOID)DcbPtr, (PVOID)&dcb, sizeof(dcb), NULL)) {
return FALSE;
}
ListAddr = DcbPtr + FIELD_OFFSET( DUMP_CONTROL_BLOCK, MiniportQueue );
Next = dcb.MiniportQueue.Flink;
if (Next == NULL) {
return FALSE;
}
while ((ULONG)Next != ListAddr) {
mpNode = CONTAINING_RECORD( Next, MINIPORT_NODE, ListEntry );
if (!DbgReadMemory( hthd->hprc, (PVOID)mpNode, (PVOID)&mpNodeBuf, sizeof(MINIPORT_NODE), NULL )) {
return FALSE;
}
Next = mpNodeBuf.ListEntry.Flink;
DataTable = mpNodeBuf.DriverEntry;
if (!DataTable) {
continue;
}
if (!DbgReadMemory( hthd->hprc, (PVOID)DataTable, (PVOID)&DataTableBuffer, sizeof(LDR_DATA_TABLE_ENTRY), NULL)) {
return FALSE;
}
//
// find an empty module alias slot
//
for (i=0; i<MAX_MODULEALIAS; i++) {
if (ModuleAlias[i].ModuleName[0] == 0) {
break;
}
}
if (i == MAX_MODULEALIAS) {
//
// module alias table is full, ignore this module
//
continue;
}
//
// convert the module name to ansi
//
ZeroMemory( UnicodeBuffer, sizeof(UnicodeBuffer) );
ZeroMemory( AnsiBuffer, sizeof(AnsiBuffer) );
if (!DbgReadMemory( hthd->hprc,
(PVOID)DataTableBuffer.BaseDllName.Buffer,
(PVOID)UnicodeBuffer,
DataTableBuffer.BaseDllName.Length,
NULL )) {
continue;
}
WideCharToMultiByte(
CP_OEMCP,
0,
UnicodeBuffer,
DataTableBuffer.BaseDllName.Length / 2,
AnsiBuffer,
sizeof(AnsiBuffer),
NULL,
NULL
);
//
// establish an alias for the crash driver
//
strcpy( ModuleAlias[i].Alias, AnsiBuffer );
ModuleAlias[i].ModuleName[0] = 'c';
_splitpath( AnsiBuffer, NULL, NULL, &ModuleAlias[i].ModuleName[1], NULL );
ModuleAlias[i].ModuleName[8] = 0;
ModuleAlias[i].Special = 2; // One shot alias...
//
// reload the module
//
ReloadModule( hthd, &DataTableBuffer, FALSE, FALSE );
}
//
// now do the magic diskdump.sys driver
//
if (!DbgReadMemory( hthd->hprc, (PVOID)dcb.DiskDumpDriver, (PVOID)&DataTableBuffer, sizeof(LDR_DATA_TABLE_ENTRY), NULL)) {
return FALSE;
}
//
// change the driver name from scsiport.sys to diskdump.sys
//
DataTableBuffer.BaseDllName.Buffer = UnicodeBuffer;
InitUnicodeString( &DataTableBuffer.BaseDllName, L"diskdump.sys" );
//
// load the module
//
ReloadModule( hthd, &DataTableBuffer, FALSE, TRUE );
return TRUE;
}
BOOL
FindModuleInList(
HPRCX hprc,
LPSTR lpModName,
DWORD ListAddr,
LPIMAGEINFO ii
)
{
LIST_ENTRY List;
PLIST_ENTRY Next;
ULONG len = 0;
ULONG cb;
PLDR_DATA_TABLE_ENTRY DataTable;
LDR_DATA_TABLE_ENTRY DataTableBuffer;
UNICODE_STRING BaseName;
CHAR AnsiBuffer[512];
WCHAR UnicodeBuffer[512];
ANSI_STRING AnsiString;
NTSTATUS Status;
ii->CheckSum = 0;
ii->SizeOfImage = 0;
ii->BaseOfImage = 0;
if (!ListAddr) {
return FALSE;
}
if (!DbgReadMemory( hprc, (PVOID)ListAddr, (PVOID)&List, sizeof(LIST_ENTRY), NULL)) {
return FALSE;
}
Next = List.Flink;
if (Next == NULL) {
return FALSE;
}
while ((ULONG)Next != ListAddr) {
DataTable = CONTAINING_RECORD( Next,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks
);
if (!DbgReadMemory( hprc, (PVOID)DataTable, (PVOID)&DataTableBuffer, sizeof(LDR_DATA_TABLE_ENTRY), NULL)) {
return FALSE;
}
Next = DataTableBuffer.InLoadOrderLinks.Flink;
//
// Get the base DLL name.
//
if (DataTableBuffer.BaseDllName.Length != 0 &&
DataTableBuffer.BaseDllName.Buffer != NULL
) {
BaseName = DataTableBuffer.BaseDllName;
}
else
if (DataTableBuffer.FullDllName.Length != 0 &&
DataTableBuffer.FullDllName.Buffer != NULL
) {
BaseName = DataTableBuffer.FullDllName;
}
else {
continue;
}
if (BaseName.Length > sizeof(UnicodeBuffer)) {
continue;
}
cb = DbgReadMemory( hprc,
(PVOID)BaseName.Buffer,
(PVOID)UnicodeBuffer,
BaseName.Length,
NULL );
if (!cb) {
return FALSE;
}
BaseName.Buffer = UnicodeBuffer;
BaseName.Length = (USHORT)cb;
BaseName.MaximumLength = (USHORT)(cb + sizeof( UNICODE_NULL ));
UnicodeBuffer[ cb / sizeof( WCHAR ) ] = UNICODE_NULL;
AnsiString.Buffer = AnsiBuffer;
AnsiString.MaximumLength = 256;
Status = UnicodeStringToAnsiString(&AnsiString, &BaseName, FALSE);
if (!NT_SUCCESS(Status)) {
return FALSE;
}
AnsiString.Buffer[AnsiString.Length] = '\0';
if (_stricmp(AnsiString.Buffer, lpModName) == 0) {
ii->BaseOfImage = (DWORD)DataTableBuffer.DllBase;
ii->SizeOfImage = (DWORD)DataTableBuffer.SizeOfImage;
ii->CheckSum = (DWORD)DataTableBuffer.CheckSum;
return TRUE;
}
}
return FALSE;
}
BOOL
ReadImageInfo(
LPSTR lpImageName,
LPSTR lpFoundName,
LPSTR lpPath,
LPIMAGEINFO ii
)
/*++
Routine Description:
This routine locates the file specified by lpImageName and reads the
IMAGE_NT_HEADERS and the IMAGE_SECTION_HEADER from the image.
Arguments:
Return Value:
True on success and FALSE on failure
--*/
{
HANDLE hFile;
IMAGE_DOS_HEADER dh;
IMAGE_NT_HEADERS nh;
IMAGE_SEPARATE_DEBUG_HEADER sdh;
IMAGE_ROM_OPTIONAL_HEADER rom;
DWORD sig;
DWORD cb;
char rgch[MAX_PATH];
CHAR fname[_MAX_FNAME];
CHAR ext[_MAX_EXT];
CHAR drive[_MAX_DRIVE];
CHAR dir[_MAX_DIR];
CHAR modname[MAX_PATH];
hFile = FindExecutableImage( lpImageName, lpPath, rgch );
if (hFile) {
if (lpFoundName) {
strcpy(lpFoundName, rgch);
}
//
// read in the pe/file headers from the EXE file
//
SetFilePointer( hFile, 0, 0, FILE_BEGIN );
ReadFile( hFile, &dh, sizeof(IMAGE_DOS_HEADER), &cb, NULL );
if (dh.e_magic == IMAGE_DOS_SIGNATURE) {
SetFilePointer( hFile, dh.e_lfanew, 0, FILE_BEGIN );
} else {
SetFilePointer( hFile, 0, 0, FILE_BEGIN );
}
ReadFile( hFile, &sig, sizeof(sig), &cb, NULL );
SetFilePointer( hFile, -4, NULL, FILE_CURRENT );
if (sig != IMAGE_NT_SIGNATURE) {
ReadFile( hFile, &nh.FileHeader, sizeof(IMAGE_FILE_HEADER), &cb, NULL );
if (nh.FileHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
ReadFile( hFile, &rom, sizeof(rom), &cb, NULL );
ZeroMemory( &nh.OptionalHeader, sizeof(nh.OptionalHeader) );
nh.OptionalHeader.SizeOfImage = rom.SizeOfCode;
nh.OptionalHeader.ImageBase = rom.BaseOfCode;
} else {
CloseHandle( hFile );
return FALSE;
}
} else {
ReadFile( hFile, &nh, sizeof(nh), &cb, NULL );
}
ii->TimeStamp = nh.FileHeader.TimeDateStamp;
ii->CheckSum = nh.OptionalHeader.CheckSum;
ii->SizeOfImage = nh.OptionalHeader.SizeOfImage;
ii->BaseOfImage = nh.OptionalHeader.ImageBase;
} else {
if (lpFoundName) {
*lpFoundName = 0;
}
//
// read in the pe/file headers from the DBG file
//
hFile = FindDebugInfoFile( lpImageName, lpPath, rgch );
if (!hFile) {
_splitpath( lpImageName, NULL, NULL, fname, NULL );
sprintf( modname, "%s.dbg", fname );
hFile = FindExecutableImage( modname, lpPath, rgch );
if (!hFile) {
return FALSE;
}
}
SetFilePointer( hFile, 0, 0, FILE_BEGIN );
ReadFile( hFile, &sdh, sizeof(IMAGE_SEPARATE_DEBUG_HEADER), &cb, NULL );
nh.FileHeader.NumberOfSections = (USHORT)sdh.NumberOfSections;
ii->CheckSum = sdh.CheckSum;
ii->TimeStamp = sdh.TimeDateStamp;
ii->SizeOfImage = sdh.SizeOfImage;
ii->BaseOfImage = sdh.ImageBase;
}
cb = nh.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;
ii->NumberOfSections = nh.FileHeader.NumberOfSections;
ii->Sections = malloc( cb );
ReadFile( hFile, ii->Sections, cb, &cb, NULL );
CloseHandle( hFile );
return TRUE;
}
BOOL
LookupImageByAddress(
IN DWORD Address,
OUT PSTR ImageName
)
/*++
Routine Description:
Look in rebase.log and coffbase.txt for an image which
contains the address provided.
Arguments:
Address - Supplies the address to look for.
ImageName - Returns the name of the image if found.
Return Value:
TRUE for success, FALSE for failure. ImageName is not modified
if the search fails.
--*/
{
LPSTR RootPath;
LPSTR pstr;
char FileName[_MAX_PATH];
char Buffer[_MAX_PATH];
BOOL Replace;
DWORD ImageAddress;
DWORD Size;
FILE *File;
//
// Locate rebase.log file
//
// SymbolPath or %SystemRoot%\Symbols
//
RootPath = pstr = (LPSTR)KdOptions[KDO_SYMBOLPATH].value;
Replace = FALSE;
File = NULL;
while (File == NULL && *pstr) {
while (*pstr) {
if (*pstr == ';') {
*pstr = 0;
Replace = TRUE;
break;
}
pstr++;
}
if (SearchTreeForFile(RootPath, "rebase.log", FileName)) {
File = fopen(FileName, "r");
}
if (Replace) {
*pstr = ';';
RootPath = ++pstr;
}
}
if (!File) {
return FALSE;
}
//
// Search file for image
//
while (fgets(Buffer, sizeof(Buffer), File)) {
ImageAddress = 0xffffffff;
Size = 0xffffffff;
sscanf( Buffer, "%s %*s %*s 0x%x (size 0x%x)",
FileName, &ImageAddress, &Size);
if (Size == 0xffffffff) {
continue;
}
if (Address >= ImageAddress && Address < ImageAddress + Size) {
strcpy(ImageName, FileName);
fclose(File);
return TRUE;
}
}
fclose(File);
return FALSE;
}
VOID
ReloadModules(
HTHDX hthd,
LPSTR args
)
{
DEBUG_EVENT de;
ULONG len = 0;
int i;
HPRCX hprc;
LPRTP rtp;
CHAR fname[_MAX_FNAME];
CHAR ext[_MAX_EXT];
CHAR drive[_MAX_DRIVE];
CHAR dir[_MAX_DIR];
CHAR modname[MAX_PATH];
CHAR modpath[MAX_PATH*2];
ULONG Address;
ULONG LoadAddress;
BOOL UnloadOnly = FALSE;
PCHAR p;
//
// this is to handle the ".reload foo.exe" command
//
// we search thru the module list and find the desired module.
// the module is then unloaded and re-loaded. the module is re-loaded
// at its preferred load address.
//
if (args && *args) {
//
// skip over any white space
//
while (*args == ' ' || *args == '\t') {
args++;
}
if (args[0] == '/' && args[1] == 'u') {
UnloadOnly = TRUE;
args += 2;
while (*args == ' ' || *args == '\t') {
args++;
}
}
LoadAddress = 0;
if (p = strchr(args, '=')) {
*p = 0;
sscanf(p+1, "%x", &LoadAddress);
}
_splitpath( args, drive, dir, fname, ext );
if (p) {
*p = '=';
}
_makepath( modname, NULL, NULL, fname, ext );
if (isdigit(*args)) {
sscanf(args, "%x", &Address);
if (LookupImageByAddress(Address, modname)) {
_splitpath( modname, drive, dir, fname, ext );
}
}
hprc = HPRCFromPID( KD_PROCESSID );
for (i=0; i<hprc->cDllList; i++) {
if ((hprc->rgDllList[i].fValidDll) &&
(_stricmp(hprc->rgDllList[i].szDllName, modname) == 0)) {
UnloadModule( (DWORD)hprc->rgDllList[i].offBaseOfImage, modname );
break;
}
}
if (!UnloadOnly) {
if (dir[0]) {
sprintf( modpath, "%s%s", drive, dir );
} else {
strcpy( modpath, (LPSTR)KdOptions[KDO_SYMBOLPATH].value );
}
_makepath( modname, drive, dir, fname, ext );
if (!ReloadModulesFromList(hthd,
vs.PsLoadedModuleList,
FALSE,
modname,
LoadAddress)) {
if (!ReloadModulesFromList(hthd,
MmLoadedUserImageList,
FALSE,
modname,
LoadAddress)) {
de.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.LoadDll.hFile = NULL;
de.u.LoadDll.lpBaseOfDll = (LPVOID)LoadAddress;
de.u.LoadDll.lpImageName = modname;
de.u.LoadDll.fUnicode = FALSE;
de.u.LoadDll.nDebugInfoSize = 0;
de.u.LoadDll.dwDebugInfoFileOffset = 0;
NotifyEM(&de, hthd, 0, (LPVOID)0);
}
}
}
} else {
UnloadAllModules();
ReloadModulesFromList( hthd, vs.PsLoadedModuleList, FALSE, NULL, 0 );
ReloadModulesFromList( hthd, MmLoadedUserImageList, FALSE, NULL, 0 );
ReloadCrashModules( hthd );
InitializeKiProcessor();
}
DMPrintShellMsg( "Finished re-loading kernel modules\n" );
//
// tell the shell that the !reload is finished
//
rtp = (LPRTP)malloc(sizeof(RTP)+sizeof(DWORD));
rtp->hpid = hthd->hprc->hpid;
rtp->htid = hthd->htid;
rtp->dbc = dbcIoctlDone;
rtp->cb = sizeof(DWORD);
*(LPDWORD)rtp->rgbVar = 1;
DmTlFunc( tlfDebugPacket, rtp->hpid, sizeof(RTP)+rtp->cb, (LONG)rtp );
free( rtp );
ConsumeAllEvents();
return;
}
VOID
ClearBps( VOID )
{
DBGKD_RESTORE_BREAKPOINT bps[MAX_KD_BPS];
DWORD i;
//
// clean out the kernel's bp list
//
for (i=0; i<MAX_KD_BPS; i++) {
bps[i].BreakPointHandle = i + 1;
}
RestoreBreakPointEx( MAX_KD_BPS, bps );
return;
}
void
AddQueue(
DWORD dwType,
DWORD dwProcessId,
DWORD dwThreadId,
DWORD dwData,
DWORD dwLen
)
{
LPCQUEUE lpcq;
EnterCriticalSection(&csContinueQueue);
lpcq = lpcqFree;
assert(lpcq);
lpcqFree = lpcq->next;
lpcq->next = NULL;
if (lpcqLast) {
lpcqLast->next = lpcq;
}
lpcqLast = lpcq;
if (!lpcqFirst) {
lpcqFirst = lpcq;
}
lpcq->pid = dwProcessId;
lpcq->tid = dwThreadId;
lpcq->typ = dwType;
lpcq->len = dwLen;
if (lpcq->typ == QT_RELOAD_MODULES || lpcq->typ == QT_DEBUGSTRING) {
if (dwLen) {
lpcq->data = (DWORD) malloc( dwLen );
memcpy( (LPVOID)lpcq->data, (LPVOID)dwData, dwLen );
}
else {
lpcq->data = 0;
}
}
else {
lpcq->data = dwData;
}
if (lpcq->typ == QT_CONTINUE_DEBUG_EVENT) {
SetEvent( hEventContinue );
}
LeaveCriticalSection(&csContinueQueue);
return;
}
BOOL
DequeueOneEvent(
LPCQUEUE lpcqReturn
)
{
LPCQUEUE lpcq;
EnterCriticalSection(&csContinueQueue);
if (!lpcqFirst) {
LeaveCriticalSection(&csContinueQueue);
return FALSE;
}
lpcq = lpcqFirst;
lpcqFirst = lpcq->next;
if (lpcqFirst == NULL) {
lpcqLast = NULL;
}
lpcq->next = lpcqFree;
lpcqFree = lpcq;
if (lpcq->pid == 0 || lpcq->tid == 0) {
lpcq->pid = KD_PROCESSID;
lpcq->tid = KD_THREADID;
}
*lpcqReturn = *lpcq;
LeaveCriticalSection(&csContinueQueue);
return TRUE;
}
BOOL
DequeueAllEvents(
BOOL fForce, // force a dequeue even if the dm isn't initialized
BOOL fConsume // delete all events from the queue with no action
)
{
CQUEUE qitem;
LPCQUEUE lpcq = &qitem;
BOOL fDid = FALSE;
HTHDX hthd;
DBGKD_CONTROL_SET cs = {0};
LPSTR d;
ResetEvent(hEventContinue);
while ( DequeueOneEvent(&qitem) ) {
if (fConsume) {
if (lpcq->typ == QT_CONTINUE_DEBUG_EVENT) {
fDid = TRUE;
}
continue;
}
hthd = HTHDXFromPIDTID(lpcq->pid, lpcq->tid);
if (hthd && hthd->fContextDirty) {
DbgSetThreadContext( hthd, &hthd->context );
hthd->fContextDirty = FALSE;
}
d = (LPSTR)lpcq->data;
switch (lpcq->typ) {
case QT_CONTINUE_DEBUG_EVENT:
if (fCrashDump) {
break;
}
if (DmKdState >= S_READY || fForce) {
if (!fDid) {
fDid = TRUE;
ContinueTargetSystem( (DWORD)d, NULL );
}
}
break;
case QT_TRACE_DEBUG_EVENT:
if (fCrashDump) {
break;
}
if (DmKdState >= S_READY || fForce) {
if (!fDid) {
fDid = TRUE;
#ifdef TARGET_i386
cs.TraceFlag = 1;
cs.Dr7 = sc.ControlReport.Dr7;
cs.CurrentSymbolStart = 1;
cs.CurrentSymbolEnd = 1;
ContinueTargetSystem( (DWORD)d, &cs );
#else
ContinueTargetSystem( (DWORD)d, NULL );
#endif
}
}
break;
case QT_RELOAD_MODULES:
ReloadModules( hthd, d );
free( (LPVOID)d );
break;
case QT_REBOOT:
if (fCrashDump) {
break;
}
DMPrintShellMsg( "Target system rebooting...\n" );
DmKdPurgeCachedVirtualMemory( TRUE );
UnloadAllModules();
ZeroMemory( ContextCache, sizeof(ContextCache) );
DmKdState = S_REBOOTED;
DmKdReboot();
InitialBreak = (BOOL) KdOptions[KDO_INITIALBP].value;
KdResync = TRUE;
break;
case QT_CRASH:
if (fCrashDump) {
break;
}
DMPrintShellMsg( "Target system crashing...\n" );
DmKdCrash( (DWORD)d );
InitialBreak = (BOOL) KdOptions[KDO_INITIALBP].value;
KdResync = TRUE;
fDid = TRUE;
break;
case QT_RESYNC:
if (fCrashDump) {
break;
}
DMPrintShellMsg( "Host and target systems resynchronizing...\n" );
KdResync = TRUE;
break;
case QT_DEBUGSTRING:
DMPrintShellMsg( "%s", (LPSTR)d );
free( (LPVOID)d );
break;
}
}
return fDid;
}
VOID
WriteKernBase(
DWORD KernBase
)
{
HKEY hKeyKd;
if ( RegOpenKey( HKEY_CURRENT_USER,
"software\\microsoft\\windbg\\0012\\programs\\ntoskrnl",
&hKeyKd ) == ERROR_SUCCESS ) {
RegSetValueEx( hKeyKd, "KernBase", 0, REG_DWORD, (LPBYTE)&KernBase, sizeof(DWORD) );
RegCloseKey( hKeyKd );
}
return;
}
DWORD
ReadKernBase(
VOID
)
{
HKEY hKeyKd;
DWORD dwType;
DWORD KernBase;
DWORD dwSize;
if ( RegOpenKey( HKEY_CURRENT_USER,
"software\\microsoft\\windbg\\0012\\programs\\ntoskrnl",
&hKeyKd ) == ERROR_SUCCESS ) {
dwSize = sizeof(DWORD);
RegQueryValueEx( hKeyKd, "KernBase", NULL, &dwType, (LPBYTE)&KernBase, &dwSize );
RegCloseKey( hKeyKd );
return KernBase;
}
return KernBase;
}
VOID
GetVersionInfo(
DWORD KernBase
)
{
CHAR buf[MAX_PATH];
if (!fCrashDump) {
ZeroMemory( &vs, sizeof(vs) );
if (DmKdGetVersion( &vs ) == STATUS_SUCCESS) {
if (!vs.KernBase) {
vs.KernBase = KernBase;
}
}
}
sprintf( buf, "Kernel Version %d", vs.MinorVersion );
if (vs.MajorVersion == 0xC) {
strcat( buf, " Checked" );
} else if (vs.MajorVersion == 0xF) {
strcat( buf, " Free" );
}
sprintf( &buf[strlen(buf)], " loaded @ 0x%08x", vs.KernBase );
DMPrintShellMsg( "%s\n", buf );
return;
}
VOID
InitializeExtraProcessors(
VOID
)
{
HTHDX hthd;
DWORD i;
DEBUG_EVENT de;
CacheProcessors = sc.NumberProcessors;
for (i = 1; i < sc.NumberProcessors; i++) {
//
// initialize the hthd
//
hthd = HTHDXFromPIDTID( KD_PROCESSID, i );
//
// refresh the context cache for this processor
//
#if defined(TARGET_i386) || defined(TARGET_PPC)
ContextCache[i].fSContextDirty = FALSE;
ContextCache[i].fSContextStale = TRUE;
#endif
ContextCache[i].fContextDirty = FALSE;
ContextCache[i].fContextStale = TRUE;
//
// tell debugger to create the thread (processor)
//
de.dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = i + 1;
de.u.CreateThread.hThread = (HANDLE)(i + 1);
de.u.CreateThread.lpThreadLocalBase = NULL;
de.u.CreateThread.lpStartAddress = NULL;
ProcessDebugEvent(&de, &sc);
WaitForSingleObject(hEventContinue,INFINITE);
}
//
// consume any continues that may have been queued
//
ConsumeAllEvents();
//
// get out of here
//
return;
}
DWORD
DmKdPollThread(
LPSTR lpProgName
)
{
char buf[512];
DWORD st;
DWORD i;
DWORD j;
BOOL fFirstSc = FALSE;
DEBUG_EVENT de;
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
HTHDX hthd;
DWORD n;
IMAGEINFO ii;
HPRCX hprc;
PollThreadId = GetCurrentThreadId();
//
// initialize the queue variables
//
n = sizeof(cqueue) / sizeof(CQUEUE);
for (i = 0; i < n-1; i++) {
cqueue[i].next = &cqueue[i+1];
}
--n;
cqueue[n].next = NULL;
lpcqFree = &cqueue[0];
lpcqFirst = NULL;
lpcqLast = NULL;
InitializeCriticalSection(&csContinueQueue);
DmKdSetMaxCacheSize( KdOptions[KDO_CACHE].value );
InitialBreak = (BOOL) KdOptions[KDO_INITIALBP].value;
//
// simulate a create process debug event
//
de.dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.CreateProcessInfo.hFile = NULL;
de.u.CreateProcessInfo.hProcess = NULL;
de.u.CreateProcessInfo.hThread = NULL;
de.u.CreateProcessInfo.lpBaseOfImage = 0;
de.u.CreateProcessInfo.dwDebugInfoFileOffset = 0;
de.u.CreateProcessInfo.nDebugInfoSize = 0;
de.u.CreateProcessInfo.lpStartAddress = NULL;
de.u.CreateProcessInfo.lpThreadLocalBase = NULL;
de.u.CreateProcessInfo.lpImageName = lpProgName;
de.u.CreateProcessInfo.fUnicode = 0;
de.u.LoadDll.nDebugInfoSize = 0;
ProcessDebugEvent(&de, &sc);
WaitForSingleObject(hEventContinue,INFINITE);
hprc = HPRCFromPID( KD_PROCESSID );
ConsumeAllEvents();
//
// simulate a loader breakpoint event
//
de.dwDebugEventCode = BREAKPOINT_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.Exception.dwFirstChance = TRUE;
de.u.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT;
de.u.Exception.ExceptionRecord.ExceptionFlags = 0;
de.u.Exception.ExceptionRecord.ExceptionRecord = NULL;
de.u.Exception.ExceptionRecord.ExceptionAddress = 0;
de.u.Exception.ExceptionRecord.NumberParameters = 0;
ProcessDebugEvent( &de, &sc );
ConsumeAllEvents();
DMPrintShellMsg( "Kernel debugger waiting to connect on com%d @ %d baud\n",
KdOptions[KDO_PORT].value,
KdOptions[KDO_BAUDRATE].value
);
setjmp( JumpBuffer );
while (TRUE) {
if (DmKdExit) {
return 0;
}
ApiIsAllowed = FALSE;
st = DmKdWaitStateChange( &sc, buf, sizeof(buf) );
if (st != STATUS_SUCCESS ) {
DEBUG_PRINT_1( "DmKdWaitStateChange failed: %08lx\n", st );
return 0;
}
ApiIsAllowed = TRUE;
fFirstSc = FALSE;
if (sc.NewState == DbgKdLoadSymbolsStateChange) {
_splitpath( buf, NULL, NULL, fname, ext );
_makepath( buf, NULL, NULL, fname, ext );
if ((DmKdState == S_UNINITIALIZED) &&
(_stricmp( buf, KERNEL_IMAGE_NAME ) == 0)) {
WriteKernBase( (DWORD)sc.u.LoadSymbols.BaseOfDll );
fFirstSc = TRUE;
}
}
if ((DmKdState == S_UNINITIALIZED) ||
(DmKdState == S_REBOOTED)) {
hthd = HTHDXFromPIDTID( KD_PROCESSID, KD_THREADID );
ContextCache[sc.Processor].fContextStale = TRUE;
DbgGetThreadContext( hthd, &sc.Context );
#if defined(TARGET_i386) || defined(TARGET_PPC)
ContextCache[sc.Processor].fSContextStale = TRUE;
#endif
} else if (sc.NewState != DbgKdLoadSymbolsStateChange) {
#if defined(TARGET_i386) || defined(TARGET_PPC)
ContextCache[sc.Processor].fSContextStale = TRUE;
#endif
//
// put the context record into the cache
//
memcpy( &ContextCache[sc.Processor].Context,
&sc.Context,
sizeof(sc.Context)
);
#if defined(TARGET_MIPS)
if ((ContextCache[sc.Processor].Context.ContextFlags &
CONTEXT_EXTENDED_INTEGER) == CONTEXT_EXTENDED_INTEGER) {
MipsContextSize = Ctx64Bit;
} else {
MipsContextSize = Ctx32Bit;
CoerceContext32To64(&ContextCache[sc.Processor].Context);
}
#endif // MIPS
}
ContextCache[sc.Processor].fContextDirty = FALSE;
ContextCache[sc.Processor].fContextStale = FALSE;
if (sc.NumberProcessors > 1 && CacheProcessors == 1) {
InitializeExtraProcessors();
}
if (DmKdState == S_REBOOTED) {
DmKdState = S_INITIALIZED;
//
// get the version/info packet from the target
//
if (fFirstSc) {
GetVersionInfo( (DWORD)sc.u.LoadSymbols.BaseOfDll );
} else {
GetVersionInfo( 0 );
}
InitialBreak = (BOOL) KdOptions[KDO_INITIALBP].value;
} else
if (DmKdState == S_UNINITIALIZED) {
DMPrintShellMsg( "Kernel Debugger connection established on com%d @ %d baud\n",
KdOptions[KDO_PORT].value,
KdOptions[KDO_BAUDRATE].value
);
//
// we're now initialized
//
DmKdState = S_INITIALIZED;
//
// get the version/info packet from the target
//
if (fFirstSc) {
GetVersionInfo( (DWORD)sc.u.LoadSymbols.BaseOfDll );
} else {
GetVersionInfo( 0 );
}
//
// clean out the kernel's bp list
//
ClearBps();
if (sc.NewState != DbgKdLoadSymbolsStateChange) {
//
// generate a mod load for the kernel/osloader
//
GenerateKernelModLoad( hprc, lpProgName );
}
DisableEmCache();
}
if (fDisconnected) {
if (sc.NewState == DbgKdLoadSymbolsStateChange) {
//
// we can process these debug events very carefully
// while disconnected from the shell. the only requirement
// is that the dm doesn't call NotifyEM while disconnected.
//
} else {
WaitForSingleObject( hEventRemoteQuit, INFINITE );
ResetEvent( hEventRemoteQuit );
}
}
if (sc.NewState == DbgKdExceptionStateChange) {
DmKdInitVirtualCacheEntry( (ULONG)sc.ProgramCounter,
(ULONG)sc.ControlReport.InstructionCount,
sc.ControlReport.InstructionStream,
TRUE
);
de.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.Exception.ExceptionRecord = sc.u.Exception.ExceptionRecord;
de.u.Exception.dwFirstChance = sc.u.Exception.FirstChance;
//
// HACK-HACK: this is here to wrongly handle the case where
// the kernel delivers an exception during initialization
// that is NOT a breakpoint exception.
//
if (DmKdState != S_READY) {
de.u.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT;
}
if (fDisconnected) {
ReConnectDebugger( &de, DmKdState == S_INITIALIZED );
}
ProcessDebugEvent( &de, &sc );
if (DmKdState == S_INITIALIZED) {
free( lpProgName );
DmKdState = S_READY;
}
}
else
if (sc.NewState == DbgKdLoadSymbolsStateChange) {
if (sc.u.LoadSymbols.UnloadSymbols) {
if (sc.u.LoadSymbols.PathNameLength == 0 &&
sc.u.LoadSymbols.BaseOfDll == (PVOID)-1 &&
sc.u.LoadSymbols.ProcessId == 0
) {
//
// the target system was just restarted
//
DMPrintShellMsg( "Target system restarted...\n" );
DmKdPurgeCachedVirtualMemory( TRUE );
UnloadAllModules();
ContinueTargetSystem( DBG_CONTINUE, NULL );
InitialBreak = (BOOL) KdOptions[KDO_INITIALBP].value;
KdResync = TRUE;
DmKdState = S_REBOOTED;
continue;
}
de.dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.UnloadDll.lpBaseOfDll = (LPVOID)sc.u.LoadSymbols.BaseOfDll;
if (fDisconnected) {
ReConnectDebugger( &de, DmKdState == S_INITIALIZED );
}
ProcessDebugEvent( &de, &sc );
ConsumeAllEvents();
ContinueTargetSystem( DBG_CONTINUE, NULL );
continue;
} else {
//
// if the mod load is for the kernel image then we must
// assume that the target system was rebooted while
// the debugger was connected. in this case we need to
// unload all modules. this will allow the mod loads that
// are forthcoming to work correctly and cause the shell to
// reinstanciate all of it's breakpoints.
//
if (_stricmp( buf, KERNEL_IMAGE_NAME ) == 0) {
UnloadAllModules();
DeleteAllBps();
ConsumeAllEvents();
}
de.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.LoadDll.hFile = (HANDLE)sc.u.LoadSymbols.CheckSum;
de.u.LoadDll.lpBaseOfDll = (LPVOID)sc.u.LoadSymbols.BaseOfDll;
de.u.LoadDll.lpImageName = buf;
de.u.LoadDll.fUnicode = FALSE;
de.u.LoadDll.nDebugInfoSize = 0;
if (sc.u.LoadSymbols.SizeOfImage == 0) {
//
// this is likely a firmware image. in such cases the boot
// loader on the target may not be able to deliver the size.
//
if (!ReadImageInfo(
buf,
NULL,
(LPSTR)KdOptions[KDO_SYMBOLPATH].value,
&ii )) {
//
// can't read the image correctly
//
DMPrintShellMsg( "Module load failed, missing size & image [%s]\n", buf );
ContinueTargetSystem( DBG_CONTINUE, NULL );
continue;
}
de.u.LoadDll.dwDebugInfoFileOffset = ii.SizeOfImage;
} else {
de.u.LoadDll.dwDebugInfoFileOffset = sc.u.LoadSymbols.SizeOfImage;
}
if (fDisconnected) {
ReConnectDebugger( &de, DmKdState == S_INITIALIZED );
}
//
// HACK ALERT
//
// this code is here to allow the presence of the
// mirrored disk drivers in a system that has crashdump
// enabled. if the modload is for a driver and the
// image name for that driver is alread present in the
// dm's module table then we alias the driver.
//
_splitpath( buf, NULL, NULL, fname, ext );
if (_stricmp( ext, ".sys" ) == 0) {
UnloadModule( (DWORD)sc.u.LoadSymbols.BaseOfDll, NULL );
for (i=0; i<(DWORD)hprc->cDllList; i++) {
if (hprc->rgDllList[i].fValidDll &&
_stricmp(hprc->rgDllList[i].szDllName,buf)==0) {
break;
}
}
if (i < (DWORD)hprc->cDllList) {
for (j=0; j<MAX_MODULEALIAS; j++) {
if (ModuleAlias[j].ModuleName[0] == 0) {
break;
}
}
if (j < MAX_MODULEALIAS) {
strcpy( ModuleAlias[j].Alias, buf );
ModuleAlias[j].ModuleName[0] = 'c';
_splitpath( buf, NULL, NULL, &ModuleAlias[j].ModuleName[1], NULL );
ModuleAlias[j].ModuleName[8] = 0;
ModuleAlias[j].Special = 2; // One shot alias...
}
}
} else {
UnloadModule( (DWORD)sc.u.LoadSymbols.BaseOfDll, buf );
}
ProcessDebugEvent( &de, &sc );
ConsumeAllEvents();
ContinueTargetSystem( DBG_CONTINUE, NULL );
continue;
}
}
if (DequeueAllEvents(FALSE,FALSE)) {
continue;
}
//
// this loop is executed while the target system is not running
// the dm sits here and processes queue event and waits for a go
//
while (TRUE) {
WaitForSingleObject( hEventContinue, 100 );
ResetEvent( hEventContinue );
if (WaitForSingleObject( hEventRemoteQuit, 0 ) == WAIT_OBJECT_0) {
fDisconnected = TRUE;
DmKdBreakIn = TRUE;
}
if (DmKdExit) {
return 0;
}
if (DmKdBreakIn || KdResync) {
break;
}
if (DequeueAllEvents(FALSE,FALSE)) {
break;
}
}
}
return 0;
}
VOID
InitializeKiProcessor(
VOID
)
{
if (!fCrashDump) {
return;
}
//
// get the address of the KiProcessorBlock
//
if (!KiProcessorBlockAddr) {
DMPrintShellMsg( "Could not get address of KiProcessorBlock\n" );
}
//
// read the contents of the KiProcessorBlock
//
DmpReadMemory( (PVOID)KiProcessorBlockAddr, &KiProcessors, sizeof(KiProcessors) );
}
DWORD
DmKdPollThreadCrash(
LPSTR lpProgName
)
{
DWORD i;
BOOL fFirstSc = FALSE;
DEBUG_EVENT de;
DWORD n;
PEXCEPTION_RECORD Exception;
LIST_ENTRY List;
PLIST_ENTRY Next;
PLDR_DATA_TABLE_ENTRY DataTable;
LDR_DATA_TABLE_ENTRY DataTableBuffer;
INT CurrProcessor;
HPRCX hprc;
PollThreadId = GetCurrentThreadId();
hprc = HPRCFromPID( KD_PROCESSID );
//
// initialize the queue variables
//
n = sizeof(cqueue) / sizeof(CQUEUE);
for (i = 0; i < n-1; i++) {
cqueue[i].next = &cqueue[i+1];
}
--n;
cqueue[n].next = NULL;
lpcqFree = &cqueue[0];
lpcqFirst = NULL;
lpcqLast = NULL;
InitializeCriticalSection(&csContinueQueue);
DmKdSetMaxCacheSize( KdOptions[KDO_CACHE].value );
InitialBreak = FALSE;
//
// initialize for crash debugging
//
if (!DmpInitialize( (LPSTR)KdOptions[KDO_CRASHDUMP].value,
&DmpContext,
&Exception,
&DmpHeader
)) {
DMPrintShellMsg( "Could not initialize crash dump file %s\n",
(LPSTR)KdOptions[KDO_CRASHDUMP].value );
return 0;
}
#if defined(TARGET_MIPS)
if (DmpHeader->MajorVersion > 3) {
MipsContextSize = Ctx64Bit;
} else {
MipsContextSize = Ctx32Bit;
CoerceContext32To64(DmpContext);
}
#endif // MIPS
memcpy( &sc.Context, DmpContext, sizeof(CONTEXT) );
memcpy( &ContextCache[0].Context, DmpContext, sizeof(CONTEXT) );
ContextCache[0].fContextDirty = FALSE;
ContextCache[0].fContextStale = FALSE;
#if defined(TARGET_i386) || defined(TARGET_PPC)
ContextCache[0].fSContextDirty = FALSE;
ContextCache[0].fSContextStale = TRUE;
#endif
sc.NewState = DbgKdExceptionStateChange;
sc.u.Exception.ExceptionRecord = *Exception;
sc.u.Exception.FirstChance = FALSE;
//
// For the createprocess and loader bp, use cpu 0
//
CurrProcessor = 0;
sc.Processor = 0;
sc.NumberProcessors = DmpHeader->NumberProcessors;
sc.ProgramCounter = Exception->ExceptionAddress;
sc.ControlReport.InstructionCount = 0;
vs.MajorVersion = (USHORT)DmpHeader->MajorVersion;
vs.MinorVersion = (USHORT)DmpHeader->MinorVersion;
vs.KernBase = 0;
vs.PsLoadedModuleList = (DWORD) DmpHeader->PsLoadedModuleList;
if (DmpReadMemory( DmpHeader->PsLoadedModuleList, (PVOID)&List, sizeof(LIST_ENTRY) )) {
Next = List.Flink;
DataTable = CONTAINING_RECORD( Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
if (DmpReadMemory( (PVOID)DataTable, (PVOID)&DataTableBuffer, sizeof(LDR_DATA_TABLE_ENTRY) )) {
vs.KernBase = (DWORD) DataTableBuffer.DllBase;
}
} else {
DMPrintShellMsg( "Could not get base of kernel 0x%08x\n",
DmpHeader->PsLoadedModuleList );
}
#if defined(TARGET_i386)
if ( DmpHeader->MachineImageType != IMAGE_FILE_MACHINE_I386)
#elif defined(TARGET_MIPS)
if ((DmpHeader->MachineImageType != IMAGE_FILE_MACHINE_R4000) &&
(DmpHeader->MachineImageType != IMAGE_FILE_MACHINE_R10000) )
#elif defined(TARGET_ALPHA)
if ( DmpHeader->MachineImageType != IMAGE_FILE_MACHINE_ALPHA)
#elif defined(TARGET_PPC)
if ( DmpHeader->MachineImageType != IMAGE_FILE_MACHINE_POWERPC)
#else
#pragma error( "unknown target machine" );
#endif
{
DMPrintShellMsg( "Dumpfile is of an unknown machine type\n" );
}
ApiIsAllowed = TRUE;
//
// simulate a create process debug event
//
de.dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.CreateProcessInfo.hFile = NULL;
de.u.CreateProcessInfo.hProcess = NULL;
de.u.CreateProcessInfo.hThread = NULL;
de.u.CreateProcessInfo.lpBaseOfImage = 0;
de.u.CreateProcessInfo.dwDebugInfoFileOffset = 0;
de.u.CreateProcessInfo.nDebugInfoSize = 0;
de.u.CreateProcessInfo.lpStartAddress = NULL;
de.u.CreateProcessInfo.lpThreadLocalBase = NULL;
de.u.CreateProcessInfo.lpImageName = lpProgName;
de.u.CreateProcessInfo.fUnicode = 0;
ProcessDebugEvent(&de, &sc);
WaitForSingleObject(hEventContinue,INFINITE);
ConsumeAllEvents();
//
// LoadDll needs this to load the right kernel symbols:
//
CacheProcessors = DmpHeader->NumberProcessors;
//
// generate a mod load for the kernel/osloader
//
GenerateKernelModLoad( hprc, lpProgName );
CurrProcessor = DmpGetCurrentProcessor();
if (CurrProcessor == -1) {
sc.Processor = 0;
} else {
sc.Processor = (USHORT)CurrProcessor;
}
//
// initialize the other processors
//
InitializeKiProcessor();
if (DmpHeader->NumberProcessors > 1) {
InitializeExtraProcessors();
}
//
// simulate a loader breakpoint event
//
de.dwDebugEventCode = BREAKPOINT_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.Exception.dwFirstChance = TRUE;
de.u.Exception.ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT;
de.u.Exception.ExceptionRecord.ExceptionFlags = 0;
de.u.Exception.ExceptionRecord.ExceptionRecord = NULL;
de.u.Exception.ExceptionRecord.ExceptionAddress = 0;
de.u.Exception.ExceptionRecord.NumberParameters = 0;
ProcessDebugEvent( &de, &sc );
ConsumeAllEvents();
DMPrintShellMsg( "Kernel Debugger connection established for %s\n",
(LPSTR)KdOptions[KDO_CRASHDUMP].value
);
//
// get the version/info packet from the target
//
GetVersionInfo( (DWORD)sc.u.LoadSymbols.BaseOfDll );
DMPrintShellMsg( "Bugcheck %08x : %08x %08x %08x %08x\n",
DmpHeader->BugCheckCode,
DmpHeader->BugCheckParameter1,
DmpHeader->BugCheckParameter2,
DmpHeader->BugCheckParameter3,
DmpHeader->BugCheckParameter4 );
DisableEmCache();
DmKdInitVirtualCacheEntry( (ULONG)sc.ProgramCounter,
(ULONG)sc.ControlReport.InstructionCount,
sc.ControlReport.InstructionStream,
TRUE
);
de.dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.Exception.ExceptionRecord = sc.u.Exception.ExceptionRecord;
de.u.Exception.dwFirstChance = sc.u.Exception.FirstChance;
ProcessDebugEvent( &de, &sc );
free( lpProgName );
while (TRUE) {
DequeueAllEvents(FALSE,FALSE);
Sleep( 1000 );
}
return 0;
}
BOOLEAN
DmKdConnectAndInitialize( LPSTR lpProgName )
{
DWORD dwThreadId;
LPSTR szProgName = malloc( MAX_PATH );
//
// bail out if we're already initialized
//
if (DmKdState != S_UNINITIALIZED) {
return TRUE;
}
szProgName[0] = '\0';
if (lpProgName) {
strcpy( szProgName, lpProgName );
}
fCrashDump = (BOOL) (KdOptions[KDO_CRASHDUMP].value != 0);
if (fCrashDump) {
hThreadDmPoll = CreateThread( NULL,
16000,
(LPTHREAD_START_ROUTINE)DmKdPollThreadCrash,
(LPVOID)szProgName,
THREAD_SET_INFORMATION,
(LPDWORD)&dwThreadId
);
} else {
//
// initialize the com port
//
if (!DmKdInitComPort( (BOOLEAN) KdOptions[KDO_USEMODEM].value )) {
DMPrintShellMsg( "Could not initialize COM%d @ %d baud, error == 0x%x\n",
KdOptions[KDO_PORT].value,
KdOptions[KDO_BAUDRATE].value,
GetLastError()
);
return FALSE;
}
hThreadDmPoll = CreateThread( NULL,
16000,
(LPTHREAD_START_ROUTINE)DmKdPollThread,
(LPVOID)szProgName,
THREAD_SET_INFORMATION,
(LPDWORD)&dwThreadId
);
}
if ( hThreadDmPoll == (HANDLE)NULL ) {
return FALSE;
}
if (!SetThreadPriority(hThreadDmPoll, THREAD_PRIORITY_ABOVE_NORMAL)) {
return FALSE;
}
KdResync = TRUE;
return TRUE;
}
VOID
DmPollTerminate( VOID )
{
extern HANDLE DmKdComPort;
extern ULONG MaxRetries;
if (hThreadDmPoll) {
DmKdExit = TRUE;
WaitForSingleObject(hThreadDmPoll, INFINITE);
DmKdState = S_UNINITIALIZED;
DeleteCriticalSection(&csContinueQueue);
ResetEvent( hEventContinue );
if (fCrashDump) {
DmpUnInitialize();
} else {
CloseHandle( DmKdComPort );
MaxRetries = 5;
}
DmKdExit = FALSE;
}
return;
}
VOID
DisableEmCache( VOID )
{
LPRTP rtp;
HTHDX hthd;
hthd = HTHDXFromPIDTID(1, 1);
rtp = (LPRTP)malloc(sizeof(RTP)+sizeof(DWORD));
rtp->hpid = hthd->hprc->hpid;
rtp->htid = hthd->htid;
rtp->dbc = dbceEnableCache;
rtp->cb = sizeof(DWORD);
*(LPDWORD)rtp->rgbVar = 1;
DmTlFunc( tlfRequest, rtp->hpid, sizeof(RTP)+rtp->cb, (LONG)rtp );
free( rtp );
return;
}
DWORD
GetSymbolAddress( LPSTR sym )
{
extern char abEMReplyBuf[];
LPRTP rtp;
HTHDX hthd;
DWORD offset;
BOOL fUseUnderBar = FALSE;
__try {
try_underbar:
hthd = HTHDXFromPIDTID(1, 1);
rtp = (LPRTP)malloc(sizeof(RTP)+strlen(sym)+16);
rtp->hpid = hthd->hprc->hpid;
rtp->htid = hthd->htid;
rtp->dbc = dbceGetOffsetFromSymbol;
rtp->cb = strlen(sym) + (fUseUnderBar ? 2 : 1);
if (fUseUnderBar) {
((LPSTR)rtp->rgbVar)[0] = '_';
memcpy( (LPSTR)rtp->rgbVar+1, sym, rtp->cb-1 );
} else {
memcpy( rtp->rgbVar, sym, rtp->cb );
}
DmTlFunc( tlfRequest, rtp->hpid, sizeof(RTP)+rtp->cb, (LONG)rtp );
free( rtp );
offset = *(LPDWORD)abEMReplyBuf;
if (!offset && !fUseUnderBar) {
fUseUnderBar = TRUE;
goto try_underbar;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
offset = 0;
}
return offset;
}
BOOL
UnloadModule(
DWORD BaseOfDll,
LPSTR NameOfDll
)
{
HPRCX hprc;
HTHDX hthd;
DEBUG_EVENT de;
DWORD i;
BOOL fUnloaded = FALSE;
hprc = HPRCFromPID( KD_PROCESSID );
hthd = HTHDXFromPIDTID( KD_PROCESSID, KD_THREADID );
//
// first lets look for the image by dll base
//
for (i=0; i<(DWORD)hprc->cDllList; i++) {
if (hprc->rgDllList[i].fValidDll && hprc->rgDllList[i].offBaseOfImage == BaseOfDll) {
de.dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.UnloadDll.lpBaseOfDll = (LPVOID)hprc->rgDllList[i].offBaseOfImage;
NotifyEM( &de, hthd, 0, (LPVOID)0);
DestroyDllLoadItem(&hprc->rgDllList[i]);
fUnloaded = TRUE;
break;
}
}
//
// now we look by dll name
//
if (NameOfDll) {
for (i=0; i<(DWORD)hprc->cDllList; i++) {
if (hprc->rgDllList[i].fValidDll &&
_stricmp(hprc->rgDllList[i].szDllName,NameOfDll)==0) {
de.dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.UnloadDll.lpBaseOfDll = (LPVOID)hprc->rgDllList[i].offBaseOfImage;
NotifyEM( &de, hthd, 0, (LPVOID)0);
DestroyDllLoadItem(&hprc->rgDllList[i]);
fUnloaded = TRUE;
break;
}
}
}
return fUnloaded;
}
VOID
UnloadAllModules(
VOID
)
{
HPRCX hprc;
HTHDX hthd;
DEBUG_EVENT de;
DWORD i;
hprc = HPRCFromPID( KD_PROCESSID );
hthd = HTHDXFromPIDTID( KD_PROCESSID, KD_THREADID );
for (i=0; i<(DWORD)hprc->cDllList; i++) {
if (hprc->rgDllList[i].fValidDll) {
de.dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.UnloadDll.lpBaseOfDll = (LPVOID)hprc->rgDllList[i].offBaseOfImage;
NotifyEM( &de, hthd, 0, (LPVOID)0);
DestroyDllLoadItem(&hprc->rgDllList[i]);
}
}
return;
}
BOOL
GenerateKernelModLoad(
HPRCX hprc,
LPSTR lpProgName
)
{
DEBUG_EVENT de;
LIST_ENTRY List;
PLDR_DATA_TABLE_ENTRY DataTable;
LDR_DATA_TABLE_ENTRY DataTableBuffer;
if (!DbgReadMemory( hprc, (PVOID)vs.PsLoadedModuleList, (PVOID)&List, sizeof(LIST_ENTRY), NULL)) {
return FALSE;
}
DataTable = CONTAINING_RECORD( List.Flink,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks
);
if (!DbgReadMemory( hprc, (PVOID)DataTable, (PVOID)&DataTableBuffer, sizeof(LDR_DATA_TABLE_ENTRY), NULL)) {
return FALSE;
}
de.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.LoadDll.hFile = (HANDLE)DataTableBuffer.CheckSum;
de.u.LoadDll.lpBaseOfDll = (LPVOID)vs.KernBase;
de.u.LoadDll.lpImageName = lpProgName;
de.u.LoadDll.fUnicode = FALSE;
de.u.LoadDll.nDebugInfoSize = 0;
de.u.LoadDll.dwDebugInfoFileOffset = DataTableBuffer.SizeOfImage;
ProcessDebugEvent( &de, &sc );
ConsumeAllEvents();
return TRUE;
}
VOID
GetKernelSymbolAddresses(
VOID
)
{
DcbAddr = GetSymbolAddress( "IopDumpControlBlock" );
MmLoadedUserImageList = GetSymbolAddress( "MmLoadedUserImageList" );
KiProcessorBlockAddr = GetSymbolAddress( "KiProcessorBlock" );
#if defined(TARGET_ALPHA)
KiPcrBaseAddress = GetSymbolAddress( "KiPcrBaseAddress" );
#endif
}
VOID
GetMachineType(
LPPROCESSOR p
)
{
#if defined(TARGET_i386)
if (DmKdState != S_INITIALIZED) {
p->Level = 3;
} else {
p->Level = sc.ProcessorLevel;
}
p->Type = mptix86;
p->Endian = endLittle;
#elif defined(TARGET_PPC)
if (DmKdState != S_INITIALIZED) {
p->Level = 601;
} else {
p->Level = sc.ProcessorLevel + 600;
}
p->Type = mptmppc;
p->Endian = endLittle;
#elif defined(TARGET_MIPS)
// BUGBUG handle R10000
p->Level = 4000;
p->Type = mptmips;
p->Endian = endLittle;
#elif defined(TARGET_ALPHA)
p->Type = mptdaxp;
p->Endian = endLittle;
p->Level = 21064;
#else
#pragma error( "unknown target machine" );
#endif
}
#if defined(TARGET_i386) || defined(TARGET_PPC)
BOOL
GetExtendedContext(
HTHDX hthd,
PKSPECIAL_REGISTERS pksr
)
{
DWORD cb;
DWORD Status;
USHORT processor;
IsApiAllowed();
NoApiForCrashDump();
if (!hthd) {
return FALSE;
}
processor = (USHORT)(hthd->tid - 1);
if (ContextCache[processor].fSContextStale) {
if (!ReadControlSpace( processor,
(PVOID)sizeof(CONTEXT),
(PVOID)pksr,
sizeof(KSPECIAL_REGISTERS),
&cb
)) {
return FALSE;
}
memcpy( &ContextCache[processor].sregs,
pksr,
sizeof(KSPECIAL_REGISTERS)
);
ContextCache[processor].fSContextStale = FALSE;
ContextCache[processor].fSContextDirty = FALSE;
return TRUE;
} else {
memcpy( pksr,
&ContextCache[processor].sregs,
sizeof(KSPECIAL_REGISTERS)
);
return TRUE;
}
return FALSE;
}
BOOL
SetExtendedContext(
HTHDX hthd,
PKSPECIAL_REGISTERS pksr
)
{
DWORD cb;
DWORD Status;
USHORT processor;
IsApiAllowed();
NoApiForCrashDump();
processor = (USHORT)(hthd->tid - 1);
Status = DmKdWriteControlSpace( processor,
(PVOID)sizeof(CONTEXT),
(PVOID)pksr,
sizeof(KSPECIAL_REGISTERS),
&cb
);
if (Status || cb != sizeof(KSPECIAL_REGISTERS)) {
return FALSE;
}
memcpy( &ContextCache[processor].sregs, pksr, sizeof(KSPECIAL_REGISTERS) );
ContextCache[processor].fSContextStale = FALSE;
ContextCache[processor].fSContextDirty = FALSE;
return TRUE;
}
#endif // i386 || PPC
DWORD
ProcessTerminateProcessCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
extern ULONG MaxRetries;
BREAKPOINT *pbpT;
BREAKPOINT *pbp;
HTHDX hthdT;
DEBUG_PRINT_2("ProcessTerminateProcessCmd called hprc=0x%x, hthd=0x%x\n",
hprc, hthd);
MaxRetries = 1;
if (!ApiIsAllowed) {
return TRUE;
}
if (hprc) {
hprc->pstate |= ps_dead;
hprc->dwExitCode = 0;
ConsumeAllProcessEvents(hprc, TRUE);
for (pbp = BPNextHprcPbp(hprc, NULL); pbp; pbp = pbpT) {
pbpT = BPNextHprcPbp(hprc, pbp);
RemoveBP(pbp);
}
for (hthdT = hprc->hthdChild; hthdT; hthdT = hthdT->nextSibling) {
if ( !(hthdT->tstate & ts_dead) ) {
hthdT->tstate |= ts_dead;
hthdT->tstate &= ~ts_stopped;
}
}
}
return TRUE;
}
VOID
ProcessAllProgFreeCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
ProcessTerminateProcessCmd(hprc, hthd, lpdbb);
}
DWORD
ProcessAsyncGoCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
XOSD xosd = xosdNone;
DEBUG_PRINT("ProcessAsyncGoCmd called\n");
hthd->tstate &= ~ts_frozen;
Reply(0, &xosd, lpdbb->hpid);
return(xosd);
}
VOID
ProcessAsyncStopCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This function is called in response to a asynchronous stop request.
In order to do this we will set breakpoints the current PC for
every thread in the system and wait for the fireworks to start.
Arguments:
hprc - Supplies a process handle
hthd - Supplies a thread handle
lpdbb - Supplies the command information packet
Return Value:
None.
--*/
{
DmKdBreakIn = TRUE;
LpDmMsg->xosdRet = xosdNone;
Reply(0, LpDmMsg, lpdbb->hpid);
return;
} /* ProcessAsyncStopCmd() */
VOID
ProcessDebugActiveCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
if (!DmKdConnectAndInitialize( KERNEL_IMAGE_NAME )) {
LpDmMsg->xosdRet = xosdFileNotFound;
} else {
LpDmMsg->xosdRet = xosdNone;
}
if (fDisconnected) {
DmKdBreakIn = TRUE;
SetEvent( hEventRemoteQuit );
}
LpDmMsg->xosdRet = xosdNone;
Reply(0, LpDmMsg, lpdbb->hpid);
}
VOID
ProcessQueryTlsBaseCmd(
HPRCX hprcx,
HTHDX hthdx,
LPDBB lpdbb
)
/*++
Routine Description:
This function is called in response to an EM request to get the base
of the thread local storage for a given thread and DLL.
Arguments:
hprcx - Supplies a process handle
hthdx - Supplies a thread handle
lpdbb - Supplies the command information packet
Return Value:
None.
--*/
{
LpDmMsg->xosdRet = xosdUnknown;
Reply( sizeof(ADDR), LpDmMsg, lpdbb->hpid );
return;
} /* ProcessQueryTlsBaseCmd() */
VOID
ProcessQuerySelectorCmd(
HPRCX hprcx,
HTHDX hthdx,
LPDBB lpdbb
)
/*++
Routine Description:
This command is send from the EM to fill-in a LDT_ENTRY structure
for a given selector.
Arguments:
hprcx - Supplies the handle to the process
hthdx - Supplies the handle to the thread and is optional
lpdbb - Supplies the pointer to the full query packet
Return Value:
None.
--*/
{
XOSD xosd;
xosd = xosdInvalidSelector;
Reply( sizeof(xosd), &xosd, lpdbb->hpid);
return;
}
VOID
ProcessReloadModulesCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This command is send from the EM to cause all modules to be reloaded.
Arguments:
hprcx - Supplies the handle to the process
hthdx - Supplies the handle to the thread and is optional
lpdbb - Supplies the pointer to the full query packet
Return Value:
None.
--*/
{
XOSD xosd;
LPIOL lpiol = (LPIOL) lpdbb->rgbVar;
AddQueue( QT_RELOAD_MODULES,
hprc->pid,
hthd->tid,
*((PULONG)lpiol->rgbVar),
0
);
xosd = xosdNone;
Reply( sizeof(xosd), &xosd, lpdbb->hpid);
return;
}
VOID
ProcessVirtualQueryCmd(
HPRCX hprc,
LPDBB lpdbb
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
#define vaddr(va) ((hprc->fRomImage) ? d[iDll].offBaseOfImage+(va) : (va))
ADDR addr;
DWORD cb;
PDLLLOAD_ITEM d = prcList->next->rgDllList;
PMEMORY_BASIC_INFORMATION lpmbi = (PMEMORY_BASIC_INFORMATION)LpDmMsg->rgb;
XOSD xosd = xosdNone;
static int iDll = 0;
static PIMAGE_SECTION_HEADER s = NULL;
addr = *(LPADDR)(lpdbb->rgbVar);
lpmbi->BaseAddress = (LPVOID)(addr.addr.off & (PAGE_SIZE - 1));
lpmbi->RegionSize = PAGE_SIZE;
// first guess
lpmbi->AllocationBase = lpmbi->BaseAddress;
lpmbi->Protect = PAGE_READWRITE;
lpmbi->AllocationProtect = PAGE_READWRITE;
lpmbi->State = MEM_COMMIT;
lpmbi->Type = MEM_PRIVATE;
//
// the following code is necessary to determine if the requested
// base address is in a page that contains code. if the base address
// meets these conditions then reply that it is executable.
//
if ( !s ||
addr.addr.off < vaddr(s->VirtualAddress) ||
addr.addr.off >= vaddr(s->VirtualAddress+s->SizeOfRawData) ) {
for (iDll=0; iDll<prcList->next->cDllList; iDll++) {
if (addr.addr.off >= d[iDll].offBaseOfImage &&
addr.addr.off < d[iDll].offBaseOfImage+d[iDll].cbImage) {
s = d[iDll].Sections;
cb = d[iDll].NumberOfSections;
while (cb) {
if (addr.addr.off >= vaddr(s->VirtualAddress) &&
addr.addr.off < vaddr(s->VirtualAddress+s->SizeOfRawData) )
{
break;
}
else {
s++;
cb--;
}
}
if (cb == 0) {
s = NULL;
}
break;
}
}
}
if (s) {
lpmbi->BaseAddress = (LPVOID)(vaddr(s->VirtualAddress));
lpmbi->RegionSize = vaddr(s->VirtualAddress);
switch ( s->Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE |
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE) ) {
case IMAGE_SCN_MEM_EXECUTE:
lpmbi->Protect =
lpmbi->AllocationProtect = PAGE_EXECUTE;
break;
case IMAGE_SCN_CNT_CODE:
case (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE):
lpmbi->Protect =
lpmbi->AllocationProtect = PAGE_EXECUTE_READ;
break;
case (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE):
lpmbi->Protect =
lpmbi->AllocationProtect = PAGE_EXECUTE_READWRITE;
break;
// This one probably never happens
case (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE):
lpmbi->Protect =
lpmbi->AllocationProtect = PAGE_EXECUTE_READWRITE;
break;
case IMAGE_SCN_MEM_READ:
lpmbi->Protect =
lpmbi->AllocationProtect = PAGE_READONLY;
break;
case (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE):
lpmbi->Protect =
lpmbi->AllocationProtect = PAGE_READWRITE;
break;
// This one probably never happens
case IMAGE_SCN_MEM_WRITE:
lpmbi->Protect =
lpmbi->AllocationProtect = PAGE_READWRITE;
break;
case 0:
lpmbi->Protect =
lpmbi->AllocationProtect = PAGE_NOACCESS;
break;
}
}
LpDmMsg->xosdRet = xosd;
Reply( sizeof(MEMORY_BASIC_INFORMATION), LpDmMsg, lpdbb->hpid );
return;
}
VOID
ProcessGetDmInfoCmd(
HPRCX hprc,
LPDBB lpdbb,
DWORD cb
)
{
extern DBGKD_GET_VERSION vs;
LPDMINFO lpi = (LPDMINFO)LpDmMsg->rgb;
LpDmMsg->xosdRet = xosdNone;
lpi->fAsync = 0;
lpi->fHasThreads = 1;
lpi->fReturnStep = 0;
//lpi->fRemote = ???
lpi->fAsyncStop = 1;
lpi->fAlwaysFlat = 1;
lpi->fHasReload = 1;
#ifdef HAS_DEBUG_REGS
lpi->cbSpecialRegs = sizeof(KSPECIAL_REGISTERS);
#else
lpi->cbSpecialRegs = 0;
#endif
lpi->MajorVersion = vs.MajorVersion;
lpi->MinorVersion = vs.MinorVersion;
lpi->Breakpoints = bptsExec |
bptsDataC |
bptsDataW |
bptsDataR |
bptsDataExec;
GetMachineType(&lpi->Processor);
//
// hack so that TL can call tlfGetVersion before
// reply buffer is initialized.
//
if ( cb >= (sizeof(DBB) + sizeof(DMINFO)) ) {
memcpy(lpdbb->rgbVar, lpi, sizeof(DMINFO));
}
Reply( sizeof(DMINFO), LpDmMsg, lpdbb->hpid );
}
#ifdef HAS_DEBUG_REGS
VOID
ProcessGetExtendedContextCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
PKSPECIAL_REGISTERS pksr = (PKSPECIAL_REGISTERS)LpDmMsg->rgb;
if (GetExtendedContext( hthd, pksr )) {
LpDmMsg->xosdRet = xosdUnknown;
} else {
LpDmMsg->xosdRet = xosdNone;
}
Reply(sizeof(KSPECIAL_REGISTERS), LpDmMsg, lpdbb->hpid);
}
void
ProcessSetExtendedContextCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
PKSPECIAL_REGISTERS pksr = (PKSPECIAL_REGISTERS)lpdbb->rgbVar;
if (SetExtendedContext( hthd, pksr )) {
LpDmMsg->xosdRet = xosdUnknown;
} else {
LpDmMsg->xosdRet = xosdNone;
}
Reply(0, LpDmMsg, lpdbb->hpid);
}
#endif // HAS_DEBUG_REGS
void
ProcessGetSectionsCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
DWORD dwBaseOfDll = *((LPDWORD) lpdbb->rgbVar);
LPOBJD rgobjd = (LPOBJD) LpDmMsg->rgb;
IMAGE_DOS_HEADER dh;
IMAGE_NT_HEADERS nh;
PIMAGE_SECTION_HEADER sec;
IMAGE_ROM_OPTIONAL_HEADER rom;
DWORD fpos;
DWORD iobj;
DWORD offset;
DWORD cbObject;
DWORD iDll;
DWORD sig;
IMAGEINFO ii;
//
// find the module
//
for (iDll=0; iDll<(DWORD)hprc->cDllList; iDll++) {
if (hprc->rgDllList[iDll].offBaseOfImage == dwBaseOfDll) {
if (hprc->rgDllList[iDll].sec) {
sec = hprc->rgDllList[iDll].sec;
nh.FileHeader.NumberOfSections =
(USHORT)hprc->rgDllList[iDll].NumberOfSections;
} else {
fpos = dwBaseOfDll;
if (!DbgReadMemory( hprc, (LPVOID)fpos, &dh, sizeof(IMAGE_DOS_HEADER), NULL )) {
break;
}
if (dh.e_magic == IMAGE_DOS_SIGNATURE) {
fpos += dh.e_lfanew;
} else {
fpos = dwBaseOfDll;
}
if (!DbgReadMemory( hprc, (LPVOID)fpos, &sig, sizeof(sig), NULL )) {
break;
}
if (sig != IMAGE_NT_SIGNATURE) {
if (!DbgReadMemory( hprc, (LPVOID)fpos, &nh.FileHeader, sizeof(IMAGE_FILE_HEADER), NULL )) {
break;
}
fpos += sizeof(IMAGE_FILE_HEADER);
if (nh.FileHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
if (!DbgReadMemory( hprc, (LPVOID)fpos, &rom, sizeof(rom), NULL )) {
break;
}
ZeroMemory( &nh.OptionalHeader, sizeof(nh.OptionalHeader) );
nh.OptionalHeader.SizeOfImage = rom.SizeOfCode;
nh.OptionalHeader.ImageBase = rom.BaseOfCode;
} else {
//
// maybe its a firmware image?
//
if (! ReadImageInfo(
hprc->rgDllList[iDll].szDllName,
NULL,
(LPSTR)KdOptions[KDO_SYMBOLPATH].value,
&ii )) {
//
// can't read the image correctly
//
LpDmMsg->xosdRet = xosdUnknown;
Reply(0, LpDmMsg, lpdbb->hpid);
return;
}
sec = ii.Sections;
nh.FileHeader.NumberOfSections = (USHORT)ii.NumberOfSections;
nh.FileHeader.SizeOfOptionalHeader = IMAGE_SIZEOF_ROM_OPTIONAL_HEADER;
}
} else {
if (!DbgReadMemory( hprc, (LPVOID)fpos, &nh, sizeof(IMAGE_NT_HEADERS), NULL )) {
break;
}
fpos += sizeof(IMAGE_NT_HEADERS);
if (nh.Signature != IMAGE_NT_SIGNATURE) {
break;
}
if (hprc->rgDllList[iDll].TimeStamp == 0) {
hprc->rgDllList[iDll].TimeStamp = nh.FileHeader.TimeDateStamp;
}
if (hprc->rgDllList[iDll].CheckSum == 0) {
hprc->rgDllList[iDll].CheckSum = nh.OptionalHeader.CheckSum;
}
sec = malloc( nh.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER );
if (!sec) {
break;
}
DbgReadMemory( hprc, (LPVOID)fpos, sec, nh.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER, NULL );
}
}
if (hprc->rgDllList[iDll].Sections == NULL) {
hprc->rgDllList[iDll].Sections = sec;
hprc->rgDllList[iDll].NumberOfSections =
nh.FileHeader.NumberOfSections;
if (nh.FileHeader.SizeOfOptionalHeader !=
IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
for (iobj=0; iobj<nh.FileHeader.NumberOfSections; iobj++) {
hprc->rgDllList[iDll].Sections[iobj].VirtualAddress +=
(DWORD)dwBaseOfDll;
}
}
}
*((LPDWORD)LpDmMsg->rgb) = nh.FileHeader.NumberOfSections;
rgobjd = (LPOBJD) (LpDmMsg->rgb + sizeof(DWORD));
//
// Set up the descriptors for each of the section headers
// so that the EM can map between section numbers and flat
// addresses.
//
for (iobj=0; iobj<nh.FileHeader.NumberOfSections; iobj++) {
offset = hprc->rgDllList[iDll].Sections[iobj].VirtualAddress;
cbObject =
hprc->rgDllList[iDll].Sections[iobj].Misc.VirtualSize;
if (cbObject == 0) {
cbObject =
hprc->rgDllList[iDll].Sections[iobj].SizeOfRawData;
}
rgobjd[iobj].offset = offset;
rgobjd[iobj].cb = cbObject;
rgobjd[iobj].wPad = 1;
#ifdef TARGET_i386
if (IMAGE_SCN_CNT_CODE &
hprc->rgDllList[iDll].Sections[iobj].Characteristics) {
rgobjd[iobj].wSel = (WORD) hprc->rgDllList[iDll].SegCs;
} else {
rgobjd[iobj].wSel = (WORD) hprc->rgDllList[iDll].SegDs;
}
#else
rgobjd[iobj].wSel = 0;
#endif
}
LpDmMsg->xosdRet = xosdNone;
Reply( sizeof(DWORD) +
(hprc->rgDllList[iDll].NumberOfSections * sizeof(OBJD)),
LpDmMsg,
lpdbb->hpid);
return;
}
}
LpDmMsg->xosdRet = xosdUnknown;
Reply(0, LpDmMsg, lpdbb->hpid);
}
VOID
ProcessIoctlGenericCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
static USHORT Processor = (USHORT)-1;
LPIOL lpiol = (LPIOL)lpdbb->rgbVar;
PIOCTLGENERIC pig = (PIOCTLGENERIC)lpiol->rgbVar;
PPROCESSORINFO pi;
PREADCONTROLSPACE prc;
PIOSPACE pis;
PIOSPACE_EX pisex;
PPHYSICAL phy;
DWORD len;
PKDHELP KdHelp;
static ULONG SavedThread;
if (!ApiIsAllowed) {
LpDmMsg->xosdRet = xosdUnknown;
Reply( sizeof(IOCTLGENERIC)+pig->length, LpDmMsg, lpdbb->hpid );
return;
}
switch( pig->ioctlSubType ) {
case IG_READ_CONTROL_SPACE:
prc = (PREADCONTROLSPACE) pig->data;
if ((SHORT)prc->Processor == -1) {
if (Processor == (USHORT)-1) {
prc->Processor = sc.Processor;
} else {
prc->Processor = Processor;
}
}
if (!ReadControlSpace( (USHORT)prc->Processor,
(PVOID)prc->Address,
(PVOID)prc->Buf,
prc->BufLen,
&len
)) {
LpDmMsg->xosdRet = xosdUnknown;
Reply(0, LpDmMsg, lpdbb->hpid);
}
prc->BufLen = len;
break;
case IG_WRITE_CONTROL_SPACE:
Reply(0, LpDmMsg, lpdbb->hpid);
return;
case IG_READ_IO_SPACE:
pis = (PIOSPACE) pig->data;
if (DmKdReadIoSpace( (PVOID)pis->Address,
&pis->Data, pis->Length ) != STATUS_SUCCESS) {
pis->Length = 0;
}
break;
case IG_WRITE_IO_SPACE:
pis = (PIOSPACE) pig->data;
if (DmKdWriteIoSpace( (PVOID)pis->Address,
pis->Data, pis->Length ) != STATUS_SUCCESS) {
pis->Length = 0;
}
break;
case IG_READ_IO_SPACE_EX:
pisex = (PIOSPACE_EX) pig->data;
if (DmKdReadIoSpaceEx(
(PVOID)pisex->Address,
&pisex->Data,
pisex->Length,
pisex->InterfaceType,
pisex->BusNumber,
pisex->AddressSpace
) != STATUS_SUCCESS) {
pisex->Length = 0;
}
break;
case IG_WRITE_IO_SPACE_EX:
pisex = (PIOSPACE_EX) pig->data;
if (DmKdWriteIoSpaceEx(
(PVOID)pisex->Address,
pisex->Data,
pisex->Length,
pisex->InterfaceType,
pisex->BusNumber,
pisex->AddressSpace
) != STATUS_SUCCESS) {
pisex->Length = 0;
}
break;
case IG_READ_PHYSICAL:
phy = (PPHYSICAL) pig->data;
if (DmKdReadPhysicalMemory( phy->Address, phy->Buf, phy->BufLen, &len )) {
phy->BufLen = 0;
}
break;
case IG_WRITE_PHYSICAL:
phy = (PPHYSICAL) pig->data;
if (DmKdWritePhysicalMemory( phy->Address, phy->Buf, phy->BufLen, &len )) {
phy->BufLen = 0;
}
break;
case IG_DM_PARAMS:
ParseDmParams( (LPSTR)pig->data );
Reply(0, LpDmMsg, lpdbb->hpid);
return;
case IG_KD_CONTEXT:
pi = (PPROCESSORINFO) pig->data;
pi->Processor = sc.Processor;
pi->NumberProcessors = (USHORT)sc.NumberProcessors;
break;
case IG_RELOAD:
AddQueue( QT_RELOAD_MODULES,
0,
0,
(DWORD)pig->data,
strlen((LPSTR)pig->data)+1 );
break;
case IG_PAGEIN:
if (DmKdPageIn( ((PULONG)pig->data)[0] ) == STATUS_SUCCESS) {
LpDmMsg->xosdRet = xosdNone;
} else {
LpDmMsg->xosdRet = xosdUnknown;
}
break;
case IG_CHANGE_PROC:
Processor = (USHORT)((PULONG)pig->data)[0];
break;
case IG_KSTACK_HELP:
KdHelp = (PKDHELP)pig->data;
KdHelp->Thread = SavedThread? SavedThread : (DWORD)sc.Thread;
SavedThread = 0;
KdHelp->KiCallUserMode = vs.KiCallUserMode;
KdHelp->ThCallbackStack = vs.ThCallbackStack;
KdHelp->NextCallback = vs.NextCallback;
KdHelp->FramePointer = vs.FramePointer;
KdHelp->KeUserCallbackDispatcher = vs.KeUserCallbackDispatcher;
break;
case IG_SET_THREAD:
memcpy(&SavedThread, pig->data, sizeof(ULONG));
break;
default:
LpDmMsg->xosdRet = xosdUnknown;
Reply(0, LpDmMsg, lpdbb->hpid);
return;
}
len = sizeof(IOCTLGENERIC) + pig->length;
memcpy( LpDmMsg->rgb, pig, len );
LpDmMsg->xosdRet = xosdNone;
Reply( sizeof(IOCTLGENERIC)+pig->length, LpDmMsg, lpdbb->hpid );
}
VOID
ProcessIoctlCustomCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
LPIOL lpiol = (LPIOL)lpdbb->rgbVar;
LPSTR p = lpiol->rgbVar;
LpDmMsg->xosdRet = xosdUnsupported;
//
// parse the command
//
while (*p && !isspace(*p++));
if (*p) {
*(p-1) = '\0';
}
//
// process the command
//
if (_stricmp( lpiol->rgbVar, "resync" ) == 0) {
DMPrintShellMsg( "Host and target systems resynchronizing...\n" );
KdResync = TRUE;
LpDmMsg->xosdRet = xosdNone;
} else
if (_stricmp( lpiol->rgbVar, "cache" ) == 0) {
ProcessCacheCmd(p);
LpDmMsg->xosdRet = xosdNone;
} else
if (_stricmp( lpiol->rgbVar, "reboot" ) == 0) {
if (ApiIsAllowed) {
AddQueue( QT_REBOOT, 0, 0, 0, 0 );
LpDmMsg->xosdRet = xosdNone;
} else {
LpDmMsg->xosdRet = xosdUnknown;
}
} else
if (_stricmp( lpiol->rgbVar, "crash" ) == 0) {
if (ApiIsAllowed) {
AddQueue( QT_CRASH, 0, 0, CRASH_BUGCHECK_CODE, 0 );
LpDmMsg->xosdRet = xosdNone;
} else {
LpDmMsg->xosdRet = xosdUnknown;
}
} else
if ( !_stricmp(lpiol->rgbVar, "FastStep") ) {
fSmartRangeStep = TRUE;
LpDmMsg->xosdRet = xosdNone;
} else
if ( !_stricmp(lpiol->rgbVar, "SlowStep") ) {
fSmartRangeStep = FALSE;
LpDmMsg->xosdRet = xosdNone;
} else
if ( !_stricmp(lpiol->rgbVar, "trace") ) {
fPacketTrace = !fPacketTrace;
LpDmMsg->xosdRet = xosdNone;
}
//
// send back our response
//
Reply(0, LpDmMsg, lpdbb->hpid);
}