Windows2000/private/windbg64/debugger/dm/kdapi.c
2020-09-30 17:12:32 +02:00

4868 lines
135 KiB
C

/*++
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
--*/
#include "precomp.h"
#pragma hdrstop
// structures & defines for queue management
typedef struct tagCQUEUE {
struct tagCQUEUE *next;
DWORD pid;
DWORD tid;
DWORD typ;
DWORD len;
DWORD64 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_IA64)
KSPECIAL_REGISTERS sregs;
BOOL fSContextStale;
BOOL fSContextDirty;
#endif // i386
BOOL fContextStale;
BOOL fContextDirty;
} CONTEXTCACHE, *LPCONTEXTCACHE;
CONTEXTCACHE ContextCache[MAXIMUM_PROCESSORS];
DWORD CacheProcessors = 1; // up machine by default
USHORT ContextSize = 0;
extern MODULEALIAS ModuleAlias[];
// Debug data cache
typedef struct _DEBUG_DATA_CACHE {
LIST_ENTRY List;
DWORD Time;
DBGKD_DEBUG_DATA_HEADER64 Block;
} DEBUG_DATA_CACHE, *PDEBUG_DATA_CACHE;
LIST_ENTRY DebugDataCacheList;
KDDEBUGGER_DATA64 KdDebuggerData;
BOOL LoadKdDataBlock(VOID);
//#define GetNtDebuggerData(NAME) (LoadKdDataBlock() ? KdDebuggerData.NAME: GetSymbolAddress("nt!"#NAME))
// globals
DWORD DmKdState = S_UNINITIALIZED;
BOOL DmKdExit;
DBGKD_WAIT_STATE_CHANGE64 sc;
BOOL fScDirty;
HANDLE hEventContinue;
BOOL fCrashDump;
DBGKD_WRITE_BREAKPOINT64 bps[64];
BOOL bpcheck[64];
HANDLE hThreadDmPoll;
DBGKD_GET_VERSION64 vs;
PDUMP_HEADER _DmpHeader;
char szProgName[MAX_PATH];
DWORD PollThreadId;
PKPRCB KiProcessors[MAXIMUM_PROCESSORS];
PCONTEXT DmpContext;
BOOL fPacketTrace;
DWORD LastStopTime;
#define DUMPHEADER(f) ((PDUMP_HEADER)_DmpHeader)->f
// kernel symbol addresses
ULONG64 DcbAddr;
ULONG64 MmLoadedUserImageList;
ULONG64 KiPcrBaseAddress;
ULONG64 KiProcessorBlockAddr;
CRITICAL_SECTION csApiInterlock;
CRITICAL_SECTION csSynchronizeTargetInterlock;
#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 CRITICAL_SECTION csProcessDebugEvent;
extern BOOL fSmartRangeStep;
extern HANDLE hEventNoDebuggee;
extern HANDLE hEventRemoteQuit;
extern BOOL fDisconnected;
extern BOOL fUseRoot;
extern char nameBuffer[];
DWORD64 GetSymbolAddress( LPSTR sym );
BOOL UnloadModule( DWORD64 BaseOfDll, LPSTR NameOfDll );
VOID UnloadAllModules( VOID );
VOID DisableEmCache( VOID );
VOID InitializeKiProcessor(VOID);
VOID ProcessCacheCmd(LPSTR pchCommand);
VOID GetKernelSymbolAddresses(VOID);
BOOL
DbgReadMemory(
HPRCX hprc,
ULONG64 lpBaseAddress,
PVOID lpBuffer,
DWORD nSize,
PDWORD lpcbRead
)
{
DWORD cb;
int iDll;
int iobj;
static PIMAGE_SECTION_HEADER s = NULL;
static ULONG64 SavedBaseOfImage = 0;
BOOL non_discardable = FALSE;
PDLLLOAD_ITEM d;
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 && lpBaseAddress >= SavedBaseOfImage + s->VirtualAddress && lpBaseAddress < SavedBaseOfImage + 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++) {
assert( Is64PtrSE(d[iDll].offBaseOfImage) );
if (lpBaseAddress >= d[iDll].offBaseOfImage && 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;
SavedBaseOfImage = d[iDll].offBaseOfImage & 0xffffffff00000000UI64;
cb = d[iDll].NumberOfSections;
while (cb) {
if (lpBaseAddress >= SavedBaseOfImage + s->VirtualAddress && lpBaseAddress < SavedBaseOfImage + 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( (DWORD64)lpBaseAddress, lpBuffer, nSize );
} else {
if (DmKdReadCachedVirtualMemory( 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, 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 defined(TARGET_IA64)
// restore template to MLI if displaced instruction is MOVL and in range
if(((bp->flags & BREAKPOINT_IA64_MOVL) && (offset >= 0)) && ((GetAddrOff(bp->addr) & 0xf) == 4)) {
*((char *)lpb + offset - 4) &= ~(0x1e);
*((char *)lpb + offset - 4) |= 0x4;
}
#endif
}
}
}
}
if (cb > 0) {
if (lpcbRead) {
*lpcbRead = cb;
}
return TRUE;
} else {
return FALSE;
}
}
BOOL DbgWriteMemory(HPRCX hprc, ULONG64 lpBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpcbWrite)
{
ULONG cb;
if (nSize == 0) {
return TRUE;
}
if (fCrashDump) {
cb = DmpWriteMemory( (DWORD64)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;
}
}
ULONG DbgReadNtHeader(ULONG64 BaseOfDll, PIMAGE_NT_HEADERS64 pNtHeaders)
{
ULONG Result;
ULONG Status;
//IMAGE_NT_HEADERS ImNtHdr;
IMAGE_DOS_HEADER ImDosHdr;
ZeroMemory(pNtHeaders, sizeof(*pNtHeaders) );
// Get the DOS hdr
Status = DmKdReadMemoryWrapper(BaseOfDll, (PVOID)&ImDosHdr, sizeof(ImDosHdr), &Result);
if ( sizeof(ImDosHdr) != Result ) {
// Error reading header
return Status;
}
// Get the NT hdr
if (ImDosHdr.e_magic == IMAGE_DOS_SIGNATURE) {
DWORD64 dw64NtHdrAddress = BaseOfDll + ImDosHdr.e_lfanew;
Status = DmKdReadMemoryWrapper(dw64NtHdrAddress,
//(PVOID)&ImNtHdr,
//sizeof(ImNtHdr)
pNtHeaders,
sizeof(*pNtHeaders),
&Result
);
}
return Status;
}
BOOL DbgGetThreadContext(IN HTHDX hthd, OUT LPCONTEXT lpContext)
{
BOOL rc = TRUE;
USHORT processor;
DWORD Flags = lpContext->ContextFlags;
DPRINT(1, ( "DbgGetThreadContext( 0x%p )\n", lpContext ));
if (!hthd) {
return FALSE;
}
processor = (USHORT)hthd->tid - 1;
if (fCrashDump) {
if (processor == sc.Processor && KiProcessors[processor] == 0) {
memcpy( lpContext, DmpContext, ContextSize);
rc = TRUE;
} else {
rc = DmpGetContext( processor, lpContext );
}
} else {
if (ContextCache[processor].fContextStale) {
rc = (DmKdGetContext( processor, &ContextCache[processor].Context ) == STATUS_SUCCESS);
if (rc) {
ContextCache[processor].fContextDirty = FALSE;
ContextCache[processor].fContextStale = FALSE;
}
}
if (rc) {
memcpy( lpContext, &ContextCache[processor].Context, ContextSize );
}
}
if (rc) {
hthd->fContextStale = FALSE;
}
return rc;
}
BOOL DbgSetThreadContext(IN HTHDX hthd, IN LPCONTEXT lpContext)
{
BOOL rc = TRUE;
USHORT processor;
DEBUG_PRINT_1( "DbgSetThreadContext( 0x%p )\n", lpContext );
NoApiForCrashDump();
processor = (USHORT)hthd->tid - 1;
memcpy( &ContextCache[processor].Context, lpContext, ContextSize );
if (lpContext != &hthd->context) {
memcpy(&hthd->context, &ContextCache[processor].Context, ContextSize );
}
ContextCache[processor].fContextDirty = FALSE;
ContextCache[processor].fContextStale = FALSE;
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);
NoApiForCrashDump();
if (DmKdWriteBreakPoint( GetAddrOff(Breakpoint->addr), &Breakpoint->hBreakPoint ) != STATUS_SUCCESS) {
rc = FALSE;
}
return rc;
}
BOOL WriteBreakPointEx(IN HTHDX hthd, IN ULONG BreakPointCount, IN OUT PDBGKD_WRITE_BREAKPOINT64 BreakPoints, IN ULONG ContinueStatus)
{
BOOL rc = TRUE;
assert( BreakPointCount > 0 );
assert( BreakPoints );
DEBUG_PRINT_2( "WriteBreakPointEx( %d, 0x%016I64x )\n", BreakPointCount, (ULONGLONG) BreakPoints);
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 );
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%016I64x )\n", BreakPointCount, (ULONGLONG)BreakPointHandles );
NoApiForCrashDump();
if (DmKdRestoreBreakPointEx( BreakPointCount, BreakPointHandles ) != STATUS_SUCCESS) {
rc = FALSE;
}
return rc;
}
BOOL ReadControlSpace(USHORT Processor, ULONG64 TargetBaseAddress, PVOID UserInterfaceBuffer, ULONG TransferCount, PULONG ActualBytesRead)
{
DWORD Status;
if (fCrashDump) {
return DmpReadControlSpace(Processor, (DWORD64)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;
// Api lock remains held until target system stops
TakeApiLock();
if (ControlSet) {
rc = DmKdContinue2( ContinueStatus, ControlSet );
} else {
rc = DmKdContinue( ContinueStatus );
}
ReleaseApiLock();
}
ULONG UnicodeStringToAnsiString(PANSI_STRING DestinationString, PUNICODE_STRING64 SourceString, BOOL AllocateDestinationString)
{
if (AllocateDestinationString) {
DestinationString->Buffer = MHAlloc( DestinationString->MaximumLength );
if (!DestinationString->Buffer) {
return 1;
}
}
DestinationString->Length = (WORD)WideCharToMultiByte(CP_ACP,
WC_COMPOSITECHECK,
(PVOID)SourceString->Buffer,
SourceString->Length / 2,
(PVOID)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_ENTRY64 DataTableBuffer,
BOOL fDontUseLoadAddr,
BOOL fLocalBuffer
)
{
UNICODE_STRING64 BaseName;
CHAR AnsiBuffer[512];
WCHAR UnicodeBuffer[512];
ANSI_STRING AnsiString;
NTSTATUS Status;
DEBUG_EVENT64 de;
CHAR fname[_MAX_FNAME];
CHAR ext[_MAX_EXT];
ULONG cb;
LPBYTE lpbPacket;
WORD cbPacket;
// Get the base DLL name.
if (DataTableBuffer->BaseDllName.Length != 0 &&
DataTableBuffer->BaseDllName.Buffer != 0 ) {
BaseName = DataTableBuffer->BaseDllName;
} else
if (DataTableBuffer->FullDllName.Length != 0 &&
DataTableBuffer->FullDllName.Buffer != 0 ) {
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, BaseName.Buffer, (PVOID)UnicodeBuffer, BaseName.Length, &cb )) {
return FALSE;
}
BaseName.Buffer = (UINT_PTR)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 : DataTableBuffer->DllBase;
de.u.LoadDll.lpImageName = (UINT_PTR)AnsiString.Buffer;
de.u.LoadDll.dwDebugInfoFileOffset = DataTableBuffer->SizeOfImage;
de.u.LoadDll.fUnicode = FALSE;
de.u.LoadDll.nDebugInfoSize = 0;
assert( Is64PtrSE(de.u.LoadDll.lpBaseOfDll) );
if (LoadDll(&de, hthd, &cbPacket, &lpbPacket, FALSE) && (cbPacket != 0)) {
NotifyEM(&de, hthd, cbPacket, (UINT_PTR)lpbPacket);
}
return TRUE;
}
BOOL
ReloadModulesFromList(
HTHDX hthd,
ULONG64 ListAddr,
BOOL fDontUseLoadAddr,
LPSTR JustLoadThisOne,
ULONG64 UseThisAddress
)
{
LIST_ENTRY64 List;
DWORDLONG Next;
ULONG len = 0;
DWORDLONG DataTable;
LDR_DATA_TABLE_ENTRY64 DataTableBuffer;
WCHAR UnicodeBuffer[_MAX_PATH];
WCHAR UnicodeBuffer2[_MAX_PATH];
int Len;
BOOL LoadedSomething;
assert( Is64PtrSE(ListAddr) );
assert( Is64PtrSE(UseThisAddress) );
if (!ListAddr) {
return FALSE;
}
// convert the module name to unicode
*UnicodeBuffer = 0;
if (JustLoadThisOne && *JustLoadThisOne) {
Len = _tcslen(JustLoadThisOne);
MultiByteToWideChar(CP_OEMCP, 0, JustLoadThisOne, Len, UnicodeBuffer, sizeof(UnicodeBuffer));
}
if (!NT_SUCCESS(DmKdReadListEntry(ListAddr, &List))) {
return FALSE;
}
Next = List.Flink;
if (Next == 0) {
return FALSE;
}
LoadedSomething = FALSE;
while (Next != ListAddr) {
if (DmKdPtr64) {
DataTable = CONTAINING_RECORD64( Next,
LDR_DATA_TABLE_ENTRY64,
InLoadOrderLinks
);
} else {
DataTable = SE32To64( CONTAINING_RECORD32( Next,
LDR_DATA_TABLE_ENTRY32,
InLoadOrderLinks
));
}
if (!NT_SUCCESS(DmKdReadLoaderEntry( DataTable, &DataTableBuffer ))) {
break;
}
Next = DataTableBuffer.InLoadOrderLinks.Flink;
if (!(JustLoadThisOne && *JustLoadThisOne) ) {
ReloadModule( hthd, &DataTableBuffer, fDontUseLoadAddr, FALSE );
LoadedSomething = TRUE;
} else {
if (2*Len == DataTableBuffer.BaseDllName.Length) {
if (!DbgReadMemory( hthd->hprc,
DataTableBuffer.BaseDllName.Buffer,
(PVOID)UnicodeBuffer2,
DataTableBuffer.BaseDllName.Length,
NULL )) {
continue;
}
if (_wcsnicmp(UnicodeBuffer, UnicodeBuffer2, Len) == 0) {
if (UseThisAddress) {
DataTableBuffer.DllBase = UseThisAddress;
}
ReloadModule( hthd, &DataTableBuffer, fDontUseLoadAddr, FALSE );
LoadedSomething = TRUE;
break;
}
}
}
}
return LoadedSomething;
}
#if 0
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
_tcscpy( 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;
}
#endif
BOOL
FindModuleInList(
HPRCX hprc,
LPSTR lpModName,
ULONG64 ListAddr,
LPIMAGEINFO ii
)
{
LIST_ENTRY64 List;
ULONG64 Next;
ULONG len = 0;
ULONG cb;
ULONG64 DataTable;
LDR_DATA_TABLE_ENTRY64 DataTableBuffer;
UNICODE_STRING64 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 (!NT_SUCCESS(DmKdReadListEntry(ListAddr, &List))) {
return FALSE;
}
Next = List.Flink;
if (Next == 0) {
return FALSE;
}
while (Next != ListAddr) {
if (DmKdPtr64) {
DataTable = CONTAINING_RECORD64( Next,
LDR_DATA_TABLE_ENTRY64,
InLoadOrderLinks
);
} else {
DataTable = SE32To64( CONTAINING_RECORD32( Next,
LDR_DATA_TABLE_ENTRY32,
InLoadOrderLinks
));
}
if (!NT_SUCCESS(DmKdReadLoaderEntry( DataTable, &DataTableBuffer))) {
return FALSE;
}
Next = DataTableBuffer.InLoadOrderLinks.Flink;
// Get the base DLL name.
if (DataTableBuffer.BaseDllName.Length != 0 &&
DataTableBuffer.BaseDllName.Buffer != 0
) {
BaseName = DataTableBuffer.BaseDllName;
}
else
if (DataTableBuffer.FullDllName.Length != 0 &&
DataTableBuffer.FullDllName.Buffer != 0
) {
BaseName = DataTableBuffer.FullDllName;
}
else {
continue;
}
if (BaseName.Length > sizeof(UnicodeBuffer)) {
continue;
}
cb = DbgReadMemory( hprc,
BaseName.Buffer,
(PVOID)UnicodeBuffer,
BaseName.Length,
NULL );
if (!cb) {
return FALSE;
}
BaseName.Buffer = (UINT_PTR)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 = DataTableBuffer.DllBase;
ii->SizeOfImage = DataTableBuffer.SizeOfImage;
ii->CheckSum = 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) {
_tcscpy(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 = SE32To64(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 = SE32To64(sdh.ImageBase);
}
cb = nh.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;
ii->NumberOfSections = nh.FileHeader.NumberOfSections;
ii->Sections = MHAlloc( cb );
ReadFile( hFile, ii->Sections, cb, &cb, NULL );
CloseHandle( hFile );
return TRUE;
}
BOOL
LookupImageByAddress(
IN DWORD64 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
assert( Is64PtrSE(Address) );
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%p (size 0x%x)",
FileName,
&ImageAddress,
&Size);
if (Size == 0xffffffff) {
continue;
}
if (Address >= ImageAddress && Address < ImageAddress + Size) {
_tcscpy(ImageName, FileName);
fclose(File);
return TRUE;
}
}
fclose(File);
return FALSE;
}
VOID
ReloadModules(
HTHDX hthd,
LPSTR args
)
{
DEBUG_EVENT64 de = {0};
ULONG len = 0;
int i = 0;
HPRCX hprc = 0;
LPRTP rtp = 0;
CHAR fname[_MAX_FNAME] = {0};
CHAR ext[_MAX_EXT] = {0};
CHAR drive[_MAX_DRIVE] = {0};
CHAR dir[_MAX_DIR] = {0};
CHAR modname[MAX_PATH] = {0};
ULONG64 Address = 0;
ULONG64 LoadAddress = 0;
BOOL UnloadOnly = FALSE;
PCHAR p = 0;
BOOL LoadUsermodeModules = TRUE;
BOOL ReallyVerbose = FALSE;
BOOL UsedArgument = FALSE;
DWORD dw = 0;
// 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.
while (args && *args) {
// skip over any white space
while (*args == ' ' || *args == '\t') {
args++;
}
if (args[0] == '/' || args[0] == '-') {
args++;
while (*args > ' ') {
switch (*args++) {
case 'n':
LoadUsermodeModules = FALSE;
break;
case 'u':
UnloadOnly = TRUE;
break;
case 'v':
ReallyVerbose = TRUE;
break;
default:
DMPrintShellMsg("bangReload: unknown option '%c'\n", args[-1]);
DMPrintShellMsg("usage: !reload [flags] [module] ...\n");
DMPrintShellMsg(" flags: /n do not load from usermode list\n");
DMPrintShellMsg(" /u unload symbols, no reload\n");
DMPrintShellMsg(" /v verbose\n");
goto bail;
}
}
} else if (*args) {
UsedArgument = TRUE;
LoadAddress = 0;
if (p = _tcschr(args, '=')) {
*p = 0;
sscanf(p+1, "%I64x", &LoadAddress);
if (!Is64PtrSE(LoadAddress)) {
// Let the user know he didn't sign extend
DMPrintShellMsg("DM RELOAD WARNING: Address was not properly sign extended. "
"Automatically sign extended from %016i64x to %016i64x.",
LoadAddress, SE32To64(LoadAddress));
LoadAddress = SE32To64(LoadAddress);
}
}
_splitpath( args, drive, dir, fname, ext );
if (p) {
*p = '=';
}
_makepath( modname, NULL, NULL, fname, ext );
if (isdigit(*args)) {
sscanf(args, "%I64x", &Address);
if (!Is64PtrSE(Address)) {
// Let the user know he didn't sign extend
DMPrintShellMsg("DM RELOAD WARNING: Address was not properly sign extended. "
"Automatically sign extended from %016i64x to %016i64x.",
Address, SE32To64(Address));
Address = SE32To64(Address);
}
if (LookupImageByAddress(Address, modname)) {
_splitpath( modname, drive, dir, fname, ext );
}
}
while (*args && *args != ' ' && *args != '\t') {
args++;
}
hprc = HPRCFromPID( KD_PROCESSID );
for (i=0; i<hprc->cDllList; i++) {
if ((hprc->rgDllList[i].fValidDll) &&
(_stricmp(hprc->rgDllList[i].szDllName, modname) == 0)) {
UnloadModule( hprc->rgDllList[i].offBaseOfImage, modname );
break;
}
}
}
if (!UnloadOnly && UsedArgument) {
_makepath( modname, drive, dir, fname, ext );
if (!ReloadModulesFromList(hthd,
vs.PsLoadedModuleList,
FALSE,
modname,
LoadAddress)) {
if (!LoadUsermodeModules ||
!ReloadModulesFromList(hthd,
MmLoadedUserImageList,
FALSE,
modname,
LoadAddress)) {
LPBYTE lpbPacket;
WORD cbPacket;
de.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.LoadDll.hFile = NULL;
de.u.LoadDll.lpBaseOfDll = LoadAddress;
de.u.LoadDll.lpImageName = (UINT_PTR)modname;
de.u.LoadDll.fUnicode = FALSE;
de.u.LoadDll.nDebugInfoSize = 0;
de.u.LoadDll.dwDebugInfoFileOffset = 0;
assert( Is64PtrSE(de.u.LoadDll.lpBaseOfDll) );
if (LoadDll(&de, hthd, &cbPacket, &lpbPacket, FALSE) && (cbPacket != 0)) {
NotifyEM(&de, hthd, cbPacket, (UINT_PTR)lpbPacket);
}
// We may have just reloaded "ntkrnl".
// We may now get the correct addresses
GetKernelSymbolAddresses();
InitializeKiProcessor();
}
}
}
}
if (!UsedArgument) {
UnloadAllModules();
ReloadModulesFromList( hthd, vs.PsLoadedModuleList, FALSE, NULL, 0 );
if (LoadUsermodeModules) {
ReloadModulesFromList( hthd, MmLoadedUserImageList, FALSE, NULL, 0 );
}
//ReloadCrashModules( hthd );
// We may now get the correct addresses
GetKernelSymbolAddresses();
InitializeKiProcessor();
}
bail:
// consume all of the continues from the modloads
ConsumeAllEvents();
// tell the shell that the !reload is finished
dw = 1;
DMSendDebugPacket(dbcServiceDone,
hthd->hprc->hpid,
hthd->htid,
sizeof(DWORD),
&dw);
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,
DWORD64 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 = (UINT_PTR) MHAlloc( 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;
}
#if DBG
LPSTR QtNames[] = {
"*** QT_INVALID_EVENT",
"QT_CONTINUE_DEBUG_EVENT",
"QT_RELOAD_MODULES",
"QT_TRACE_DEBUG_EVENT",
"QT_REBOOT",
"QT_RESYNC",
"QT_DEBUGSTRING",
"QT_CRASH"
};
#endif
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 DBG
//DMPrintShellMsg("DequeueAllEvents: consuming %s\n", QtNames[lpcq->typ]);
#endif
switch (lpcq->typ) {
case QT_CONTINUE_DEBUG_EVENT:
fDid = TRUE;
continue;
case QT_TRACE_DEBUG_EVENT:
case QT_REBOOT:
case QT_CRASH:
case QT_RESYNC:
continue;
case QT_DEBUGSTRING:
// don't discard debug strings
break;
case QT_RELOAD_MODULES:
// don't discard reloads
break;
}
}
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( PtrToUlong(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( PtrToUlong(d), &cs );
#else
ContinueTargetSystem( PtrToUlong(d), NULL );
#endif
}
}
break;
case QT_RELOAD_MODULES:
ReloadModules( hthd, d );
MHFree( (LPVOID)d );
break;
case QT_REBOOT:
if (fCrashDump) {
break;
}
DMPrintShellMsg( "Target system rebooting...\n" );
DmKdPurgeCachedVirtualMemory( TRUE );
UnloadAllModules();
ZeroMemory( ContextCache, sizeof(ContextCache) );
DmKdState = S_REBOOTED;
// this is equivalent to a continue, so acquire the lock
TakeApiLock();
DmKdReboot();
InitialBreak = (BOOL) KdOptions[KDO_INITIALBP].value;
KdResync = TRUE;
break;
case QT_CRASH:
if (fCrashDump) {
break;
}
DMPrintShellMsg( "Target system crashing...\n" );
DmKdCrash( PtrToUlong(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 );
MHFree( (LPVOID)d );
break;
}
}
return fDid;
}
void
InitEventQueue(
void
)
{
int n;
int i;
// initialize the queue variables
InitializeCriticalSection(&csContinueQueue);
n = sizeof(cqueue) / sizeof(CQUEUE);
for (i = 0; i < n-1; i++) {
cqueue[i].next = &cqueue[i+1];
}
cqueue[n-1].next = NULL;
lpcqFree = &cqueue[0];
lpcqFirst = NULL;
lpcqLast = NULL;
}
VOID
WriteKernBase(
DWORD64 KernBase
)
{
#if 0
HKEY hKeyKd;
if ( RegOpenKey( HKEY_CURRENT_USER,
"software\\microsoft\\windbg\\0021\\programs\\ntoskrnl",
&hKeyKd ) == ERROR_SUCCESS ) {
RegSetValueEx( hKeyKd, "KernBase", 0, REG_DWORD, (LPBYTE)&KernBase, sizeof(DWORD) );
RegCloseKey( hKeyKd );
}
#endif
return;
}
DWORD64
ReadKernBase(
VOID
)
{
#if 0
HKEY hKeyKd;
DWORD dwType;
DWORD KernBase;
DWORD dwSize;
if ( RegOpenKey( HKEY_CURRENT_USER,
"software\\microsoft\\windbg\\0021\\programs\\ntoskrnl",
&hKeyKd ) == ERROR_SUCCESS ) {
dwSize = sizeof(DWORD);
RegQueryValueEx( hKeyKd, "KernBase", NULL, &dwType, (LPBYTE)&KernBase, &dwSize );
RegCloseKey( hKeyKd );
return KernBase;
}
return KernBase;
#endif
return 0;
}
DbgGetVersion(PDBGKD_GET_VERSION64 GetVersion)
/*++
Routine Description:
Load the DBGKD_GET_VERSION packet.
If not debugging a crashdump, call DmKdGetVersion to do the work.
If it is a crashdump, conjure up the values.
--*/
{
ULONG64 Addr;
if (!fCrashDump) {
return DmKdGetVersion(GetVersion);
}
// the current build number
GetVersion->MinorVersion = (short)_DmpHeader->MinorVersion;
GetVersion->MajorVersion = (short)_DmpHeader->MajorVersion;
#if defined(TARGET_i386)
if (vs.MinorVersion < CONTEXT_SIZE_NT5_VERSION) {
ContextSize = CONTEXT_SIZE_PRE_NT5;
} else {
ContextSize = sizeof(CONTEXT);
}
#else
ContextSize = sizeof(CONTEXT);
#endif
// kd protocol version number. this should be incremented if the protocol changes.
GetVersion->ProtocolVersion = 5;
GetVersion->Flags = DBGKD_VERS_FLAG_DATA;
// This is wrong - what we really want to know is whether it is a UP or MP kernel.
if (DUMPHEADER(NumberProcessors) > 1) {
GetVersion->Flags |= DBGKD_VERS_FLAG_MP;
}
#if defined(TARGET_i386)
GetVersion->MachineType = IMAGE_FILE_MACHINE_I386;
#elif defined(TARGET_ALPHA)
GetVersion->MachineType = IMAGE_FILE_MACHINE_ALPHA;
#elif defined(TARGET_AXP64)
GetVersion->MachineType = IMAGE_FILE_MACHINE_ALPHA64;
#elif defined(TARGET_IA64)
GetVersion->MachineType = IMAGE_FILE_MACHINE_IA64;
#else
#error( "unknown target machine" );
#endif
// address of the loader table
GetVersion->PsLoadedModuleList = SEPtrTo64(_DmpHeader->PsLoadedModuleList);
// If the debugger is being initialized during boot, PsNtosImageBase
// and PsLoadedModuleList are not yet valid. KdInitSystem got the image base from the loader block.
// On the other hand, if the debugger was initialized by a bugcheck,
// it didn't get a loader block to look at, but the system was running so the other variables are valid.
if ((Addr = GetSymbolAddress( "nt!KdpNtosImageBase" )) != 0 || (Addr = GetSymbolAddress( "nt!KdpPsNtosImageBase" )) != 0) {
if (DmKdPtr64) {
DmpReadMemory( Addr, &GetVersion->KernBase, sizeof(GetVersion->KernBase) );
// Better be sign extended.
assert(Is64PtrSE(GetVersion->KernBase));
} else {
DmpReadMemory( Addr, &GetVersion->KernBase, sizeof(ULONG) );
// Sign extend what we just read.
GetVersion->KernBase = SEPtrTo64(GetVersion->KernBase);
}
}
// These values are not in the version packet in modern versions of the system.
// When debugging NT4 dumps, GetDebuggerDataBlock needs to fill in these values.
//GetVersion->ThCallbackStack = FIELD_OFFSET(KTHREAD, CallbackStack);
//GetVersion->NextCallback = FIELD_OFFSET(KCALLOUT_FRAME, CbStk);
#if defined(TARGET_i386)
//GetVersion->FramePointer = FIELD_OFFSET(KCALLOUT_FRAME, Ebp);
#endif
//GetVersion->BreakpointWithStatus = GetSymbolAddress("nt!RtlpBreakWithStatusInstruction");
//GetVersion->KiCallUserMode = GetSymbolAddress("nt!KiCallUserMode");
//GetVersion->KeUserCallbackDispatcher = GetSymbolAddress("nt!KeUserCallbackDispatcher");
GetVersion->DebuggerDataList = GetSymbolAddress( "nt!KdpDebuggerDataListHead" );
return 0;
}
VOID GetVersionInfo(DWORD64 KernBase)
{
CHAR buf[MAX_PATH];
ZeroMemory( &vs, sizeof(vs) );
if (DbgGetVersion( &vs ) == STATUS_SUCCESS) {
if (!vs.KernBase) {
vs.KernBase = KernBase;
}
}
sprintf( buf, "Kernel Version %d", vs.MinorVersion );
if (vs.MajorVersion == 0xC) {
_tcscat( buf, " Checked" );
} else if (vs.MajorVersion == 0xF) {
_tcscat( buf, " Free" );
}
sprintf( &buf[_tcslen(buf)], " loaded @ %016I64x", vs.KernBase );
DMPrintShellMsg( "%s\n", buf );
return;
}
VOID
InitializeExtraProcessors(
VOID
)
{
HTHDX hthd;
DWORD i;
DEBUG_EVENT64 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_IA64)
ContextCache[i].fSContextStale = TRUE;
ContextCache[i].fSContextDirty = FALSE;
#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 = 0;
de.u.CreateThread.lpStartAddress = 0;
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[1024] = {0};
DWORD st;
DWORD i;
DWORD j;
BOOL fFirstSc = FALSE;
DEBUG_EVENT64 de;
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
HTHDX hthd;
DWORD n;
IMAGEINFO ii;
HPRCX hprc;
PollThreadId = GetCurrentThreadId();
TakeApiLock();
DmKdSetMaxCacheSize( (ULONG)KdOptions[KDO_CACHE].value );
InitialBreak = (BOOL) KdOptions[KDO_INITIALBP].value;
InitializeListHead(&DebugDataCacheList);
// 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 = 0;
de.u.CreateProcessInfo.lpThreadLocalBase = 0;
de.u.CreateProcessInfo.lpImageName = (UINT_PTR)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 = 0;
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 );
// The first time thru we release the lock acquired and the top of the
// function.
// Subsent passes thru here will release the lock acquired in the beginning
// of the while loop, but "jumped" out of thru a longjump in the DmKdWaitStateChange
ReleaseApiLock();
while (TRUE) {
if (DmKdExit) {
goto cleanup;
}
TakeApiLock();
st = DmKdWaitStateChange( &sc, buf, sizeof(buf) );
LastStopTime = GetTickCount();
if (st != STATUS_SUCCESS ) {
DEBUG_PRINT_1( "DmKdWaitStateChange failed: %08lx\n", st );
goto cleanup;
}
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( 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_IA64)
ContextCache[sc.Processor].fSContextStale = TRUE;
#endif
} else if (sc.NewState != DbgKdLoadSymbolsStateChange) {
#if defined(TARGET_i386) || defined(TARGET_IA64)
ContextCache[sc.Processor].fSContextStale = TRUE;
#endif
// put the context record into the cache
memcpy( &ContextCache[sc.Processor].Context,
&sc.Context,
sizeof(sc.Context)
);
}
ContextCache[sc.Processor].fContextDirty = FALSE;
ContextCache[sc.Processor].fContextStale = FALSE;
//ReleaseApiLock();
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( 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( 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( 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 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) {
DmKdState = S_READY;
}
}
else
if (sc.NewState == DbgKdLoadSymbolsStateChange) {
if (sc.u.LoadSymbols.UnloadSymbols) {
if (sc.u.LoadSymbols.PathNameLength == 0 &&
sc.u.LoadSymbols.BaseOfDll == (ULONG64)-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;
ReleaseApiLock();
continue;
}
de.dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.UnloadDll.lpBaseOfDll = sc.u.LoadSymbols.BaseOfDll;
assert( Is64PtrSE(sc.u.LoadSymbols.BaseOfDll) );
if (fDisconnected) {
ReConnectDebugger( &de, DmKdState == S_INITIALIZED );
}
ProcessDebugEvent( &de, &sc );
ConsumeAllEvents();
ContinueTargetSystem( DBG_CONTINUE, NULL );
ReleaseApiLock();
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 (_tcsicmp( buf, KERNEL_IMAGE_NAME ) == 0) {
UnloadAllModules();
DeleteAllBps();
ConsumeAllEvents();
}
assert( Is64PtrSE(sc.u.LoadSymbols.BaseOfDll) );
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 = sc.u.LoadSymbols.BaseOfDll;
de.u.LoadDll.lpImageName = (UINT_PTR)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 );
ReleaseApiLock();
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 already present in the
// dm's module table then we alias the driver.
_splitpath( buf, NULL, NULL, fname, ext );
if (_tcsicmp( ext, ".sys" ) == 0) {
UnloadModule( sc.u.LoadSymbols.BaseOfDll, NULL );
for (i=0; i<(DWORD)hprc->cDllList; i++) {
if (hprc->rgDllList[i].fValidDll &&
_tcsicmp(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) {
_tcscpy( 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( sc.u.LoadSymbols.BaseOfDll, buf );
}
ProcessDebugEvent( &de, &sc );
if (DmKdState == S_INITIALIZED) {
DmKdState = S_READY;
}
}
}
if (DequeueAllEvents(FALSE,FALSE)) {
ReleaseApiLock();
continue;
}
ReleaseApiLock();
// this loop is executed while the target system is not running
// the dm sits here and processes queue events 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) {
goto cleanup;
}
if (DmKdBreakIn || KdResync) {
break;
}
if (DequeueAllEvents(FALSE,FALSE)) {
break;
}
}
}
cleanup:
MHFree( lpProgName );
return 0;
}
VOID
InitializeKiProcessor(
VOID
)
{
if (!fCrashDump) {
return;
}
// get the address of the KiProcessorBlock
if (!KiProcessorBlockAddr) {
DMPrintShellMsg( "Could not get address of KiProcessorBlock\n" );
} else {
// read the contents of the KiProcessorBlock
DmpReadMemory( KiProcessorBlockAddr, &KiProcessors, sizeof(KiProcessors) );
}
}
DWORD
DmKdPollThreadCrash(
LPSTR lpProgName
)
{
DWORD i;
BOOL fFirstSc = FALSE;
DEBUG_EVENT64 de;
DWORD n;
EXCEPTION_RECORD64 Exception64;
PEXCEPTION_RECORD Exception;
LIST_ENTRY64 List;
ULONG64 Next;
ULONG64 DataTable;
LDR_DATA_TABLE_ENTRY64 DataTableBuffer;
INT CurrProcessor;
HPRCX hprc;
CRASHDUMP_VERSION_INFO VersionInfo;
PollThreadId = GetCurrentThreadId();
hprc = HPRCFromPID( KD_PROCESSID );
DmKdExit = FALSE;
// 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);
InitializeListHead(&DebugDataCacheList);
DmKdSetMaxCacheSize( (ULONG)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;
}
// fix up version bugs
DmpDetectVersionParameters( &VersionInfo );
DmKdPtr64 = (VersionInfo.PointerSize == 64);
if (DmKdPtr64) {
Exception64 = *(PEXCEPTION_RECORD64)Exception;
} else {
ExceptionRecord32To64((PEXCEPTION_RECORD32)Exception, &Exception64);
}
vs.MajorVersion = (USHORT)DUMPHEADER(MajorVersion);
vs.MinorVersion = (USHORT)DUMPHEADER(MinorVersion);
vs.KernBase = 0;
#if defined(TARGET_i386)
if (vs.MinorVersion < CONTEXT_SIZE_NT5_VERSION) {
ContextSize = CONTEXT_SIZE_PRE_NT5;
} else {
ContextSize = sizeof(CONTEXT);
}
#else
ContextSize = sizeof(CONTEXT);
#endif
memcpy( &sc.Context, DmpContext, ContextSize );
memcpy( &ContextCache[0].Context, DmpContext, ContextSize );
sc.NewState = DbgKdExceptionStateChange;
sc.u.Exception.ExceptionRecord = Exception64;
sc.u.Exception.FirstChance = FALSE;
// For the createprocess and loader bp, use cpu 0
CurrProcessor = 0;
sc.Processor = 0;
sc.NumberProcessors = DUMPHEADER(NumberProcessors);
sc.ProgramCounter = Exception64.ExceptionAddress;
sc.ControlReport.InstructionCount = 0;
// Set Context flags
ContextCache[0].fContextDirty = FALSE;
ContextCache[0].fContextStale = FALSE;
#if defined(TARGET_i386) || defined(TARGET_IA64)
ContextCache[0].fSContextDirty = FALSE;
ContextCache[0].fSContextStale = TRUE;
#endif
vs.PsLoadedModuleList = (ULONG64)DUMPHEADER(PsLoadedModuleList);
if (NT_SUCCESS(DmKdReadListEntry( vs.PsLoadedModuleList, &List ))) {
Next = List.Flink;
if (DmKdPtr64) {
DataTable = CONTAINING_RECORD64( Next, LDR_DATA_TABLE_ENTRY64, InLoadOrderLinks );
} else {
DataTable = SE32To64( CONTAINING_RECORD32( Next, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks ));
}
if (NT_SUCCESS(DmKdReadLoaderEntry( DataTable, (PVOID)&DataTableBuffer ))) {
vs.KernBase = DataTableBuffer.DllBase;
}
} else {
DMPrintShellMsg( "Could not get base of kernel %08I64x\n",
vs.PsLoadedModuleList );
}
#if defined(TARGET_i386)
if ( DUMPHEADER(MachineImageType) != IMAGE_FILE_MACHINE_I386)
#elif defined(TARGET_ALPHA)
if ( DUMPHEADER(MachineImageType) != IMAGE_FILE_MACHINE_ALPHA)
#elif defined(TARGET_AXP64)
if ( DUMPHEADER(MachineImageType) != IMAGE_FILE_MACHINE_ALPHA64)
#elif defined(TARGET_IA64)
if ( DUMPHEADER(MachineImageType) != IMAGE_FILE_MACHINE_IA64)
#else
#pragma error( "unknown target machine" );
#endif
{
DMPrintShellMsg( "Dumpfile is of an unknown machine type\n" );
}
// 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 = 0;
de.u.CreateProcessInfo.lpThreadLocalBase = 0;
de.u.CreateProcessInfo.lpImageName = (UINT_PTR)lpProgName;
de.u.CreateProcessInfo.fUnicode = 0;
ProcessDebugEvent(&de, &sc);
WaitForSingleObject(hEventContinue,INFINITE);
ConsumeAllEvents();
// LoadDll needs this to load the right kernel symbols:
CacheProcessors = DUMPHEADER(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 (DUMPHEADER(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 = 0;
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
if (DbgKdLoadSymbolsStateChange == sc.NewState) {
// We have a new module address, let's process it.
GetVersionInfo( (DWORD)sc.u.LoadSymbols.BaseOfDll );
} else {
// 'sc' contains exception data, not symbol information.
// BUGBUG - Why do we even do this here? To force the symbol loads?
// Whatever value we have is probably a good guess anyway. In most
// cases, the value of "vs.KernBase" is usually correct by the time
// it gets here. So just pass it in.
GetVersionInfo( vs.KernBase );
}
DMPrintShellMsg( "Bugcheck %08x : %08x %08x %08x %08x\n",
DUMPHEADER(BugCheckCode),
DUMPHEADER(BugCheckParameter1),
DUMPHEADER(BugCheckParameter2),
DUMPHEADER(BugCheckParameter3),
DUMPHEADER(BugCheckParameter4) );
DisableEmCache();
DmKdInitVirtualCacheEntry( 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 );
MHFree( lpProgName );
while (!DmKdExit) {
DequeueAllEvents(FALSE,FALSE);
Sleep( 1000 );
}
return 0;
}
BOOL
DmKdConnectAndInitialize(
LPSTR lpProgName
)
{
DWORD dwThreadId;
LPSTR szProgName = MHAlloc( MAX_PATH );
// bail out if we're already initialized
if (DmKdState != S_UNINITIALIZED) {
return TRUE;
}
szProgName[0] = '\0';
if (lpProgName) {
_tcscpy( 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( (BOOL) 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;
MaxRetries = 1;
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)MHAlloc(FIELD_OFFSET(RTP, rgbVar)+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, FIELD_OFFSET(RTP, rgbVar)+rtp->cb, (UINT_PTR)rtp );
MHFree( rtp );
return;
}
ULONG64
GetSymbolAddress(
LPSTR sym
)
{
extern char abEMReplyBuf[];
LPRTP rtp;
HTHDX hthd;
DWORD64 offset;
BOOL fUseUnderBar = FALSE;
__try {
try_underbar:
hthd = HTHDXFromPIDTID(1, 1);
rtp = (LPRTP)MHAlloc(FIELD_OFFSET(RTP, rgbVar)+_tcslen(sym)+16);
rtp->hpid = hthd->hprc->hpid;
rtp->htid = hthd->htid;
rtp->dbc = dbceGetOffsetFromSymbol;
rtp->cb = _tcslen(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, FIELD_OFFSET(RTP, rgbVar)+rtp->cb, (UINT_PTR)rtp );
MHFree( rtp );
offset = *(PDWORD64)abEMReplyBuf;
if (!offset && !fUseUnderBar) {
fUseUnderBar = TRUE;
goto try_underbar;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
offset = 0;
}
assert(Is64PtrSE(offset));
return offset;
}
BOOL
UnloadModule(
DWORD64 BaseOfDll,
LPSTR NameOfDll
)
{
HPRCX hprc;
HTHDX hthd;
DEBUG_EVENT64 de;
DWORD i;
BOOL fUnloaded = FALSE;
assert( Is64PtrSE(BaseOfDll) );
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) {
assert( Is64PtrSE(hprc->rgDllList[i].offBaseOfImage) );
if (hprc->rgDllList[i].offBaseOfImage == BaseOfDll) {
de.dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.UnloadDll.lpBaseOfDll = hprc->rgDllList[i].offBaseOfImage;
NotifyEM( &de, hthd, 0, 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) {
assert( Is64PtrSE(hprc->rgDllList[i].offBaseOfImage) );
if (_tcsicmp(hprc->rgDllList[i].szDllName,NameOfDll)==0) {
de.dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.UnloadDll.lpBaseOfDll = hprc->rgDllList[i].offBaseOfImage;
NotifyEM( &de, hthd, 0, 0);
fUnloaded = TRUE;
break;
}
}
}
}
return fUnloaded;
}
VOID
UnloadAllModules(
VOID
)
{
HPRCX hprc;
HTHDX hthd;
DEBUG_EVENT64 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) {
assert( Is64PtrSE(hprc->rgDllList[i].offBaseOfImage) );
de.dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
de.dwProcessId = KD_PROCESSID;
de.dwThreadId = KD_THREADID;
de.u.UnloadDll.lpBaseOfDll = hprc->rgDllList[i].offBaseOfImage;
NotifyEM( &de, hthd, 0, 0);
DestroyDllLoadItem(&hprc->rgDllList[i]);
}
}
return;
}
BOOL
GenerateKernelModLoad(
HPRCX hprc,
LPSTR lpProgName
)
{
DEBUG_EVENT64 de;
LIST_ENTRY64 List;
ULONG64 DataTable;
LDR_DATA_TABLE_ENTRY64 DataTableBuffer;
LPBYTE lpbPacket;
WORD cbPacket;
HTHDX hthd;
hthd = HTHDXFromPIDTID( KD_PROCESSID, 1 );
if (!NT_SUCCESS(DmKdReadListEntry( vs.PsLoadedModuleList, &List ))) {
return FALSE;
}
if (DmKdPtr64) {
DataTable = CONTAINING_RECORD64( List.Flink,
LDR_DATA_TABLE_ENTRY64,
InLoadOrderLinks
);
} else {
DataTable = SE32To64( CONTAINING_RECORD32( List.Flink,
LDR_DATA_TABLE_ENTRY32,
InLoadOrderLinks
));
}
if (!NT_SUCCESS(DmKdReadLoaderEntry(DataTable, &DataTableBuffer ))) {
return FALSE;
}
assert( Is64PtrSE(vs.KernBase) );
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 = vs.KernBase;
de.u.LoadDll.lpImageName = (UINT_PTR)lpProgName;
de.u.LoadDll.fUnicode = FALSE;
de.u.LoadDll.nDebugInfoSize = 0;
de.u.LoadDll.dwDebugInfoFileOffset = DataTableBuffer.SizeOfImage;
if (LoadDll(&de, hthd, &cbPacket, &lpbPacket, FALSE) && (cbPacket != 0)) {
NotifyEM(&de, hthd, cbPacket, (ULONG64)lpbPacket);
}
GetKernelSymbolAddresses();
ConsumeAllEvents();
return TRUE;
}
VOID
GetKernelSymbolAddresses(
VOID
)
{
if (fCrashDump) {
vs.DebuggerDataList = GetSymbolAddress("nt!KdpDebuggerDataListHead");
}
//(DcbAddr = GetNtDebuggerData( IopDumpControlBlock )) ||
if (!DcbAddr) {
DcbAddr = GetSymbolAddress( "nt!IopDumpControlBlock" );
}
if (!MmLoadedUserImageList) {
if (!LoadKdDataBlock()) {
MmLoadedUserImageList = GetSymbolAddress("nt!MmLoadedUserImageList");
}
}
//(KiProcessorBlockAddr = GetNtDebuggerData( KiProcessorBlock )) ||
if (!KiProcessorBlockAddr) {
KiProcessorBlockAddr = GetSymbolAddress( "nt!KiProcessorBlock" );
}
#if defined(TARGET_ALPHA) || defined(TARGET_AXP64)
if (!KiPcrBaseAddress) {
KiPcrBaseAddress = GetSymbolAddress( "nt!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_ALPHA)
p->Type = mptdaxp;
p->Endian = endLittle;
p->Level = 21064;
#elif defined(TARGET_AXP64)
p->Type = mptdaxp;
p->Endian = endLittle;
p->Level = 21164;
#elif defined(TARGET_IA64)
if (DmKdState != S_INITIALIZED) {
p->Level = 7;
} else {
p->Level = sc.ProcessorLevel;
}
p->Type = mptia64;
p->Endian = endLittle;
#else
#pragma error( "unknown target machine" );
#endif
}
#if defined(TARGET_i386) || defined(TARGET_IA64)
BOOL
GetExtendedContext(
HTHDX hthd,
PKSPECIAL_REGISTERS pksr
)
{
DWORD cb;
DWORD Status;
USHORT processor;
BOOL rc;
NoApiForCrashDump();
if (!hthd) {
return FALSE;
}
processor = (USHORT)(hthd->tid - 1);
if (ContextCache[processor].fSContextStale) {
if (!ReadControlSpace( processor,
ContextSize,
(PVOID)pksr,
sizeof(KSPECIAL_REGISTERS),
&cb
)) {
rc = FALSE;
} else {
memcpy( &ContextCache[processor].sregs,
pksr,
sizeof(KSPECIAL_REGISTERS)
);
ContextCache[processor].fSContextStale = FALSE;
ContextCache[processor].fSContextDirty = FALSE;
rc = TRUE;
}
} else {
memcpy( pksr,
&ContextCache[processor].sregs,
sizeof(KSPECIAL_REGISTERS)
);
rc = TRUE;
}
return rc;
}
BOOL
SetExtendedContext(
HTHDX hthd,
PKSPECIAL_REGISTERS pksr
)
{
DWORD cb;
DWORD Status;
USHORT processor;
BOOL rc;
NoApiForCrashDump();
processor = (USHORT)(hthd->tid - 1);
Status = DmKdWriteControlSpace( processor,
ContextSize,
(PVOID)pksr,
sizeof(KSPECIAL_REGISTERS),
&cb
);
if (Status || cb != sizeof(KSPECIAL_REGISTERS)) {
rc = FALSE;
} else {
memcpy( &ContextCache[processor].sregs, pksr, sizeof(KSPECIAL_REGISTERS) );
ContextCache[processor].fSContextStale = FALSE;
ContextCache[processor].fSContextDirty = FALSE;
rc = TRUE;
}
return rc;
}
#endif // i386
DWORD
ProcessTerminateProcessCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
extern ULONG MaxRetries;
BREAKPOINT *pbpT;
BREAKPOINT *pbp;
HTHDX hthdT;
DEBUG_PRINT_2("ProcessTerminateProcessCmd called hprc=0x%p, hthd=0x%p\n",
hprc, hthd);
MaxRetries = 1;
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.
--*/
{
// If we are debugging a dump file, don't
// bother trying to stop it. Just reply to it as
// if it were sucessful.
if (!fCrashDump) {
//if ( !TryApiLock() ) {
if ( !TryEnterCriticalSection(&csSynchronizeTargetInterlock) ) {
DMPrintShellMsg("DMKD: Currently busy synchronizing target and host...\n");
LpDmMsg->xosdRet = xosdUnknown;
} else {
DMPrintShellMsg("DMKD: Sending breakin packet...\n");
DmKdBreakIn = TRUE;
//ReleaseApiLock();
LeaveCriticalSection(&csSynchronizeTargetInterlock);
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 = xosdUnsupported;
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;
LPSSS lpsss = (LPSSS) lpdbb->rgbVar;
AddQueue( QT_RELOAD_MODULES,
hprc->pid,
hthd->tid,
*((PULONG)lpsss->rgbData),
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;
LPMEMINFO lpmi = (LPMEMINFO)LpDmMsg->rgb;
XOSD xosd = xosdNone;
static int iDll = 0;
static PIMAGE_SECTION_HEADER s = NULL;
#ifdef DBG
if (sizeof(s->VirtualAddress) == sizeof(DWORD64)) {
assert("Remove sign extensions");
}
#endif
ZeroMemory(lpmi, sizeof(*lpmi));
addr = *(LPADDR)(lpdbb->rgbVar);
assert( Is64PtrSE(addr.addr.off) );
lpmi->addr.addr.off = addr.addr.off & (PAGE_SIZE - 1);
lpmi->uRegionSize = PAGE_SIZE;
// first guess
lpmi->addrAllocBase = lpmi->addr;
lpmi->dwProtect = PAGE_READWRITE;
lpmi->dwAllocationProtect = PAGE_READWRITE;
lpmi->dwState = MEM_COMMIT;
lpmi->dwType = 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 (hprc->fRomImage) {
assert( Is64PtrSE(d[iDll].offBaseOfImage) );
}
if ( !s ||
addr.addr.off < SE32To64( vaddr(s->VirtualAddress) ) ||
addr.addr.off >= SE32To64( vaddr(s->VirtualAddress + s->SizeOfRawData) )
) {
for (iDll=0; iDll<prcList->next->cDllList; iDll++) {
assert( Is64PtrSE(d[iDll].offBaseOfImage) );
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 >= SE32To64( vaddr(s->VirtualAddress) ) &&
addr.addr.off < SE32To64( vaddr(s->VirtualAddress+s->SizeOfRawData) )
) {
break;
} else {
s++;
cb--;
}
}
if (cb == 0) {
s = NULL;
}
break;
}
}
}
if (s) {
lpmi->addr.addr.off = SE32To64( vaddr(s->VirtualAddress) );
lpmi->uRegionSize = SE32To64( 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:
lpmi->dwProtect =
lpmi->dwAllocationProtect = PAGE_EXECUTE;
break;
case IMAGE_SCN_CNT_CODE:
case (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE):
lpmi->dwProtect =
lpmi->dwAllocationProtect = PAGE_EXECUTE_READ;
break;
case (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_WRITE):
lpmi->dwProtect =
lpmi->dwAllocationProtect = PAGE_EXECUTE_READWRITE;
break;
// This one probably never happens
case (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE):
lpmi->dwProtect =
lpmi->dwAllocationProtect = PAGE_EXECUTE_READWRITE;
break;
case IMAGE_SCN_MEM_READ:
lpmi->dwProtect =
lpmi->dwAllocationProtect = PAGE_READONLY;
break;
case (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE):
lpmi->dwProtect =
lpmi->dwAllocationProtect = PAGE_READWRITE;
break;
// This one probably never happens
case IMAGE_SCN_MEM_WRITE:
lpmi->dwProtect =
lpmi->dwAllocationProtect = PAGE_READWRITE;
break;
case 0:
lpmi->dwProtect =
lpmi->dwAllocationProtect = PAGE_NOACCESS;
break;
}
}
assert( Is64PtrSE( lpmi->addr.addr.off ) );
assert( Is64PtrSE( lpmi->addrAllocBase.addr.off ) );
LpDmMsg->xosdRet = xosd;
Reply( sizeof(MEMINFO), LpDmMsg, lpdbb->hpid );
return;
}
VOID
ProcessGetDmInfoCmd(
HPRCX hprc,
LPDBB lpdbb,
DWORD cb
)
{
LPDMINFO lpi = (LPDMINFO)LpDmMsg->rgb;
LpDmMsg->xosdRet = xosdNone;
lpi->mAsync = asyncRun |
asyncStop;
lpi->fHasThreads = 1;
lpi->fReturnStep = 0;
//lpi->fRemote = ???
lpi->fAlwaysFlat = 0;
lpi->fHasReload = 1;
lpi->fNonLocalGoto = 0;
lpi->fKernelMode = 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);
if (DmKdState != S_INITIALIZED ||
vs.MajorVersion == 0) {
lpi->fDMInfoCacheable = FALSE;
} else {
lpi->fDMInfoCacheable = TRUE;
}
// hack so that TL can call tlfGetVersion before
// reply buffer is initialized.
if ( cb >= (FIELD_OFFSET(DBB, rgbVar) + 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
)
{
DWORD64 dwBaseOfDll = *((PDWORD64) lpdbb->rgbVar);
LPOBJD rgobjd = (LPOBJD) LpDmMsg->rgb;
IMAGE_DOS_HEADER dh;
IMAGE_NT_HEADERS nh;
PIMAGE_SECTION_HEADER sec;
IMAGE_ROM_OPTIONAL_HEADER rom;
DWORD64 fpos;
DWORD iobj;
// if offset is changed to anything other than a
// 32bit variable, modify SE32To64(offset) accordingly.
DWORD offset;
DWORD cbObject;
DWORD iDll;
DWORD sig;
IMAGEINFO ii;
assert( Is64PtrSE(dwBaseOfDll) );
// find the module
for (iDll=0; iDll<(DWORD)hprc->cDllList; iDll++) {
assert( Is64PtrSE(hprc->rgDllList[iDll].offBaseOfImage) );
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, 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, fpos, &sig, sizeof(sig), NULL )) {
break;
}
if (sig != IMAGE_NT_SIGNATURE) {
if (!DbgReadMemory( hprc, 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, 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, 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 = MHAlloc( nh.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER );
if (!sec) {
break;
}
DbgReadMemory( hprc, 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;
}
// See comment at variable declaration of offset
rgobjd[iobj].offset = SE32To64(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);
}
BOOL
GetDebuggerDataBlock(
IN HPRCX hprc,
IN OUT PDBGKD_DEBUG_DATA_HEADER64 DataBlock
)
/*++
Routine Description:
This routine walks through the kernel's debugger data block list looking
for a block with a particulat tag. If that block is found, it will be
read and returned to the caller.
A single-entry cache is used to improve the performance of debugger
extensions which query this interface frequently.
Debugger data blocks are supplied by drivers and other components. If a
driver unloads without unlinking the debugger data, the list will be broken.
If this routine encounters a broken list, it will try running through the
list in reverse order.
Arguments:
DataBlock - Supplies a pointer to block header with the OwnerTag and Size
fields filled in. The block must be Size bytes in length.
If the block is found, it will be copied into this buffer.
The size of the returned block is limited to the size specified
by the caller; this routine will not write past the end of the
supplied buffer. However, the Size field will be modified to
contain the actual size of the block in the debuggee system.
Return Value:
TRUE if a valid data block is found, FALSE otherwise.
--*/
{
DBGKD_DEBUG_DATA_HEADER64 Header;
LIST_ENTRY64 List64;
ULONG64 Next64;
ULONG64 Address;
BOOL Reverse = FALSE;
ULONG SizeToRead;
ULONG Result;
PLIST_ENTRY pList;
PDEBUG_DATA_CACHE CacheEntry = NULL;
// if block is cached, return it
pList = DebugDataCacheList.Flink;
while (pList != &DebugDataCacheList) {
CacheEntry = CONTAINING_RECORD(pList, DEBUG_DATA_CACHE, List);
pList = pList->Flink;
if (CacheEntry->Block.OwnerTag == DataBlock->OwnerTag) {
// got it - is it valid?
if (CacheEntry->Time != LastStopTime) {
// It is stale, and must be reloaded.
// if size is different, discard this block:
if (CacheEntry->Block.Size != DataBlock->Size) {
RemoveEntryList(&CacheEntry->List);
free(CacheEntry);
CacheEntry = NULL;
}
break;
} else {
// return it
memcpy(DataBlock, &CacheEntry->Block, DataBlock->Size);
return TRUE;
}
}
}
if (CacheEntry && (CacheEntry->Block.OwnerTag != DataBlock->OwnerTag)) {
CacheEntry = NULL;
}
// get list head
if (!vs.DebuggerDataList) {
DbgGetVersion( &vs );
}
if (vs.MinorVersion <= 1381) {
return FALSE;
}
if (!vs.DebuggerDataList) {
DMPrintShellMsg("DMKD: Unable to get address of debugger data list\n");
return FALSE;
}
// walk list, look for tag
if (!NT_SUCCESS(DmKdReadListEntry(vs.DebuggerDataList, &List64))) {
DMPrintShellMsg("DMKD: Unable to read debugger data list head\n");
return FALSE;
}
Next64 = List64.Flink;
if (Next64 == 0) {
DMPrintShellMsg("DMKD: Debugger data list head is NULL!\n");
return FALSE;
}
SearchList:
while (Next64 != vs.DebuggerDataList) {
//if (CheckControlC()) {
//return FALSE;
//}
if (DmKdPtr64) {
Address = CONTAINING_RECORD64(Next64, DBGKD_DEBUG_DATA_HEADER64, List);
} else {
Address = SE32To64( CONTAINING_RECORD32(Next64, DBGKD_DEBUG_DATA_HEADER32, List));
}
if (!NT_SUCCESS(DmKdReadDebuggerDataHeader(Address, &Header))) {
if (Reverse) {
DMPrintShellMsg("DMKD: Debugger data list is corrupt. Unable to locate block for %4.4s",
&DataBlock->OwnerTag);
return FALSE;
} else {
// List is broken; try it in reverse
Next64 = List64.Blink;
Reverse = TRUE;
goto SearchList;
}
}
if (Header.OwnerTag == DataBlock->OwnerTag) {
// found it
// if the requested size is different from the actual
// size, read only the smaller of the two.
// However, always return the actual size in the size field,
// so the caller can see if it does not match.
SizeToRead = DataBlock->Size;
if (Header.Size != SizeToRead) {
DMPrintShellMsg("DMKD: Debugger data block sizes do not match for component %4.4s\n",
&Header.OwnerTag);
DMPrintShellMsg("DMKD: Extension requested %d, component contains %d\n",
SizeToRead, Header.Size);
if (Header.Size < SizeToRead) {
SizeToRead = Header.Size;
}
}
if (!NT_SUCCESS(DmKdReadDebuggerDataBlock(Address, DataBlock, SizeToRead))) {
DMPrintShellMsg("DMKD: Unable to read debugger data block\n");
return FALSE;
}
if (!CacheEntry) {
CacheEntry = malloc(SizeToRead - sizeof(DBGKD_DEBUG_DATA_HEADER64) + sizeof(DEBUG_DATA_CACHE));
} else {
RemoveEntryList(&CacheEntry->List);
}
CacheEntry->Time = LastStopTime;
memcpy(&CacheEntry->Block, DataBlock, SizeToRead);
InsertHeadList(&DebugDataCacheList, &CacheEntry->List);
return TRUE;
}
if (Reverse) {
Next64 = Header.List.Blink;
} else {
Next64 = Header.List.Flink;
}
}
DMPrintShellMsg("DMKD: Debugger data block not found for %4.4s",
&DataBlock->OwnerTag);
return FALSE;
}
BOOL LoadKdDataBlock(VOID)
{
if (KdDebuggerData.Header.Size == 0) {
KdDebuggerData.Header.OwnerTag = KDBG_TAG;
KdDebuggerData.Header.Size = sizeof(KDDEBUGGER_DATA64);
if (!GetDebuggerDataBlock( HPRCFromPID( KD_PROCESSID ), (PDBGKD_DEBUG_DATA_HEADER64)&KdDebuggerData.Header)) {
KdDebuggerData.Header.Size = -1;
}
}
return KdDebuggerData.Header.Size != -1;
}
VOID
LocalProcessSystemServiceCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This function is called in response to a SystemService command from the shell.
It is used as a catch all to get and set strange information which is not covered elsewhere.
The set of SystemServices is OS and implemenation dependent.
Arguments:
hprc - Supplies a process handle
hthd - Supplies a thread handle
lpdbb - Supplies the command information packet
Return Value:
None.
--*/
{
LPSSS lpsss = (LPSSS) lpdbb->rgbVar;
switch( lpsss->ssvc ) {
default:
LpDmMsg->xosdRet = xosdUnsupported;
Reply(0, LpDmMsg, lpdbb->hpid);
return;
}
} /* LocalProcessSystemServiceCmd() */
VOID
ProcessIoctlGenericCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
LPSSS lpsss = (LPSSS)lpdbb->rgbVar;
PIOCTLGENERIC InputPig = (PIOCTLGENERIC)lpsss->rgbData;
PVOID InputBuffer = InputPig->data;
DWORD InputType = InputPig->ioctlSubType;
DWORD ReplyXosd;
DWORD ReplyLength;
PVOID ReplyBuffer;
PIOCTLGENERIC ReplyPig = (PIOCTLGENERIC)LpDmMsg->rgb;
PPROCESSORINFO pi;
PREADCONTROLSPACE prc;
PIOSPACE pis;
PIOSPACE_EX pisex;
PPHYSICAL phy;
PKDHELP64 KdHelp;
static ULONG64 SavedThread;
static USHORT Processor = (USHORT)-1;
if (!TryApiLock()) {
LpDmMsg->xosdRet = xosdUnknown;
Reply( 0, LpDmMsg, lpdbb->hpid );
return;
}
*ReplyPig = *InputPig;
ReplyBuffer = ReplyPig->data;
ReplyLength = ReplyPig->length;
ReplyXosd = xosdNone;
switch( InputPig->ioctlSubType ) {
case IG_READ_CONTROL_SPACE:
prc = (PREADCONTROLSPACE) ReplyPig->data;
*prc = *(PREADCONTROLSPACE)InputPig->data;
if ((SHORT)prc->Processor == -1) {
if (Processor == (USHORT)-1) {
prc->Processor = sc.Processor;
} else {
prc->Processor = Processor;
}
}
if (!ReadControlSpace( (USHORT)prc->Processor, prc->Address, (PVOID)prc->Buf, prc->BufLen, &prc->BufLen)) {
ReplyXosd = xosdUnknown;
ReplyLength = 0;
}
break;
case IG_WRITE_CONTROL_SPACE:
ReplyLength = 0;
break;
case IG_READ_IO_SPACE:
pis = (PIOSPACE) ReplyPig->data;
*pis = *(PIOSPACE)InputPig->data;
if (DmKdReadIoSpace( pis->Address, &pis->Data, pis->Length ) != STATUS_SUCCESS) {
pis->Length = 0;
}
break;
case IG_WRITE_IO_SPACE:
pis = (PIOSPACE) ReplyPig->data;
*pis = *(PIOSPACE)InputPig->data;
if (DmKdWriteIoSpace( pis->Address, pis->Data, pis->Length ) != STATUS_SUCCESS) {
pis->Length = 0;
}
break;
case IG_READ_IO_SPACE_EX:
pisex = (PIOSPACE_EX) ReplyPig->data;
*pisex = *(PIOSPACE_EX)InputPig->data;
if (DmKdReadIoSpaceEx(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) ReplyPig->data;
*pisex = *(PIOSPACE_EX)InputPig->data;
if (DmKdWriteIoSpaceEx(
pisex->Address,
pisex->Data,
pisex->Length,
pisex->InterfaceType,
pisex->BusNumber,
pisex->AddressSpace
) != STATUS_SUCCESS) {
pisex->Length = 0;
}
break;
case IG_READ_PHYSICAL:
phy = (PPHYSICAL) ReplyPig->data;
*phy = *(PPHYSICAL)InputPig->data;
if (DmKdReadPhysicalMemory( phy->Address, phy->Buf, phy->BufLen, &phy->BufLen )) {
phy->BufLen = 0;
}
break;
case IG_WRITE_PHYSICAL:
phy = (PPHYSICAL) ReplyPig->data;
*phy = *(PPHYSICAL)InputPig->data;
if (DmKdWritePhysicalMemory( phy->Address, phy->Buf, phy->BufLen, &phy->BufLen )) {
phy->BufLen = 0;
}
break;
case IG_DM_PARAMS:
ParseDmParams( (LPSTR)InputPig->data );
ReplyLength = 0;
break;
case IG_KD_CONTEXT:
pi = (PPROCESSORINFO) ReplyPig->data;
pi->Processor = sc.Processor;
pi->NumberProcessors = (USHORT)sc.NumberProcessors;
break;
case IG_RELOAD:
AddQueue( QT_RELOAD_MODULES, 0, 0, (DWORD64)InputPig->data, _tcslen((LPSTR)InputPig->data)+1 );
ReplyLength = 0;
break;
case IG_CHANGE_PROC:
Processor = (USHORT)((PULONG)InputPig->data)[0];
ReplyLength = 0;
break;
case IG_KSTACK_HELP:
KdHelp = (PKDHELP64)ReplyPig->data;
KdHelp->Thread = SavedThread? SavedThread : (DWORD64)sc.Thread;
SavedThread = 0;
if (LoadKdDataBlock()) {
KdHelp->KiCallUserMode = KdDebuggerData.KiCallUserMode;
KdHelp->ThCallbackStack = KdDebuggerData.ThCallbackStack;
KdHelp->NextCallback = KdDebuggerData.NextCallback;
KdHelp->FramePointer = KdDebuggerData.FramePointer;
KdHelp->KeUserCallbackDispatcher = KdDebuggerData.KeUserCallbackDispatcher;
}
ReplyLength = sizeof(KDHELP64);
break;
case IG_SET_THREAD:
SavedThread = *(PULONG64)(InputPig->data);
break;
case IG_GET_DEBUGGER_DATA:
*((PDBGKD_DEBUG_DATA_HEADER64)ReplyPig->data) = *((PDBGKD_DEBUG_DATA_HEADER64)InputPig->data);
if (!GetDebuggerDataBlock(hprc, (PDBGKD_DEBUG_DATA_HEADER64)ReplyPig->data)) {
ReplyXosd = xosdUnknown;
ReplyLength = 0;
}
break;
// BUGBUG add translation
//case IG_GET_KERNEL_VERSION:
// *((PDBGKD_GET_VERSION)ReplyPig->data) = vs;
// ReplyLength = sizeof(DBGKD_GET_VERSION);
// break;
case IG_RELOAD_SYMBOLS:
ReloadModules(hthd, (LPSTR)InputPig->data);
ReplyLength = 0;
break;
default:
ReplyXosd = xosdUnknown;
ReplyLength = 0;
break;
}
ReleaseApiLock();
ReplyPig->length = ReplyLength;
LpDmMsg->xosdRet = ReplyXosd;
Reply( ReplyLength + sizeof(IOCTLGENERIC), LpDmMsg, lpdbb->hpid );
}
VOID
ProcessSSVCCustomCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
LPSSS lpsss = (LPSSS)lpdbb->rgbVar;
LPSTR p = lpsss->rgbData;
LpDmMsg->xosdRet = xosdUnsupported;
// parse the command
while (*p && !isspace(*p++));
if (*p) {
*(p-1) = '\0';
}
// process the command
if (_tcsicmp( lpsss->rgbData, "resync" ) == 0) {
if ( !TryEnterCriticalSection(&csSynchronizeTargetInterlock) ) {
DMPrintShellMsg("DMKD: Currently busy synchronizing target and host...\n");
LpDmMsg->xosdRet = xosdUnknown;
} else {
DMPrintShellMsg( "Host and target systems resynchronizing...\n" );
KdResync = TRUE;
LeaveCriticalSection(&csSynchronizeTargetInterlock);
LpDmMsg->xosdRet = xosdNone;
}
} else if (_tcsicmp( lpsss->rgbData, "cache" ) == 0) {
ProcessCacheCmd(p);
LpDmMsg->xosdRet = xosdNone;
} else if (_tcsicmp( lpsss->rgbData, "reboot" ) == 0) {
if (TryApiLock()) {
AddQueue( QT_REBOOT, 0, 0, 0, 0 );
ReleaseApiLock();
LpDmMsg->xosdRet = xosdNone;
} else {
LpDmMsg->xosdRet = xosdUnknown;
}
} else if (_tcsicmp( lpsss->rgbData, "crash" ) == 0) {
if (TryApiLock()) {
AddQueue( QT_CRASH, 0, 0, CRASH_BUGCHECK_CODE, 0 );
ReleaseApiLock();
LpDmMsg->xosdRet = xosdNone;
} else {
LpDmMsg->xosdRet = xosdUnknown;
}
} else if ( !_tcsicmp(lpsss->rgbData, "FastStep") ) {
fSmartRangeStep = TRUE;
LpDmMsg->xosdRet = xosdNone;
} else if ( !_tcsicmp(lpsss->rgbData, "SlowStep") ) {
fSmartRangeStep = FALSE;
LpDmMsg->xosdRet = xosdNone;
} else if ( !_tcsicmp(lpsss->rgbData, "trace") ) {
fPacketTrace = !fPacketTrace;
LpDmMsg->xosdRet = xosdNone;
}
// send back our response
Reply(0, LpDmMsg, lpdbb->hpid);
}
void ContinueThreadEx(HTHDX hthd, DWORD ContinueStatus, DWORD EventType, TSTATEX NewState)
{
// If NewState is ts_running, do the "usual magic" as a special
// case. If it is anything else, set the flag to NewState
if (NewState == ts_running) {
hthd->tstate &= ~(ts_stopped | ts_first | ts_second);
hthd->tstate |= ts_running;
} else {
hthd->tstate = NewState;
}
hthd->fExceptionHandled = FALSE;
AddQueue (EventType, hthd->hprc->pid, hthd->tid, ContinueStatus, 0);
}
void ContinueProcess(HPRCX hprc)
{
HTHDX hthd;
for (hthd = hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
if (hthd->tstate & ts_stopped) {
ContinueThread(hthd);
}
}
}
void ContinueThread(HTHDX hthd)
{
DWORD ContinueStatus = DBG_CONTINUE;
if ( (hthd->tstate & (ts_first | ts_second)) && !hthd->fExceptionHandled) {
ContinueStatus = (DWORD)DBG_EXCEPTION_NOT_HANDLED;
}
ContinueThreadEx(hthd, ContinueStatus, QT_CONTINUE_DEBUG_EVENT, ts_running);
}
BOOL
GetModnameFromImage(
HPRCX hprc,
LPLOAD_DLL_DEBUG_INFO64 ldd,
LPTSTR lpName
)
/*++
Routine Description:
This routine attempts to get the name of the exe as placed in the debug section by the linker.
Arguments:
hprc -
ldd -
lpName -
Return Value:
TRUE if a name was found, FALSE if not.
The exe name is returned as an ANSI string in lpName.
--*/
{
#define ReadMem(b,s) DbgReadMemory( hprc, (address), (b), (s), NULL ); address += (s)
IMAGE_DEBUG_DIRECTORY DebugDir;
PIMAGE_DEBUG_MISC pMisc;
PIMAGE_DEBUG_MISC pT;
DWORD rva;
int nDebugDirs;
int i;
int j;
int l;
BOOL rVal = FALSE;
PVOID pExeName;
IMAGE_NT_HEADERS nh;
IMAGE_DOS_HEADER dh;
IMAGE_ROM_OPTIONAL_HEADER rom;
DWORD64 address;
DWORD sig;
PIMAGE_SECTION_HEADER pSH;
DWORD cb;
assert( Is64PtrSE(ldd->lpBaseOfDll) );
lpName[0] = 0;
address = ldd->lpBaseOfDll;
ReadMem( &dh, sizeof(dh) );
if (dh.e_magic == IMAGE_DOS_SIGNATURE) {
address = ldd->lpBaseOfDll + dh.e_lfanew;
} else {
address = ldd->lpBaseOfDll;
}
ReadMem( &sig, sizeof(sig) );
address -= sizeof(sig);
if (sig == IMAGE_NT_SIGNATURE) {
ReadMem( &nh, sizeof(nh) );
} else {
ReadMem( &nh.FileHeader, sizeof(IMAGE_FILE_HEADER) );
if (nh.FileHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
ReadMem( &rom, sizeof(rom) );
ZeroMemory( &nh.OptionalHeader, sizeof(nh.OptionalHeader) );
nh.OptionalHeader.SizeOfImage = rom.SizeOfCode;
nh.OptionalHeader.ImageBase = rom.BaseOfCode;
} else {
return FALSE;
}
}
cb = nh.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;
pSH = MHAlloc( cb );
ReadMem( pSH, cb );
nDebugDirs = nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size / sizeof(IMAGE_DEBUG_DIRECTORY);
if (!nDebugDirs) {
return FALSE;
}
rva = nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
for(i = 0; i < nh.FileHeader.NumberOfSections; i++) {
if (rva >= pSH[i].VirtualAddress && rva < pSH[i].VirtualAddress + pSH[i].SizeOfRawData) {
break;
}
}
if (i >= nh.FileHeader.NumberOfSections) {
return FALSE;
}
rva = ((rva - pSH[i].VirtualAddress) + pSH[i].VirtualAddress);
for (j = 0; j < nDebugDirs; j++) {
address = rva + (sizeof(DebugDir) * j) + ldd->lpBaseOfDll;
assert( Is64PtrSE(address) );
ReadMem( &DebugDir, sizeof(DebugDir) );
if (DebugDir.Type == IMAGE_DEBUG_TYPE_MISC) {
l = DebugDir.SizeOfData;
pMisc = pT = MHAlloc(l);
if ((ULONG)DebugDir.AddressOfRawData < pSH[i].VirtualAddress || (ULONG)DebugDir.AddressOfRawData >= pSH[i].VirtualAddress + pSH[i].SizeOfRawData) {
// the misc debug data MUST be in the .rdata section
// otherwise windbg cannot access it as it is not mapped in
continue;
}
address = (ULONG64)DebugDir.AddressOfRawData + ldd->lpBaseOfDll;
assert( Is64PtrSE(address) );
ReadMem( pMisc, l );
while (l > 0) {
if (pMisc->DataType != IMAGE_DEBUG_MISC_EXENAME) {
l -= pMisc->Length;
pMisc = (PIMAGE_DEBUG_MISC)(((LPSTR)pMisc) + pMisc->Length);
} else {
pExeName = (PVOID)&pMisc->Data[ 0 ];
if (!pMisc->Unicode) {
_tcscpy(lpName, (LPSTR)pExeName);
rVal = TRUE;
} else {
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pExeName, -1, lpName, MAX_PATH, NULL, NULL);
rVal = TRUE;
}
/*
* Undo stevewo's error
*/
if (_ftcsicmp(&lpName[_ftcslen(lpName)-4], ".DBG") == 0) {
TCHAR rgchPath[_MAX_PATH];
TCHAR rgchBase[_MAX_FNAME];
_splitpath(lpName, NULL, rgchPath, rgchBase, NULL);
if (_ftcslen(rgchPath)==4) {
rgchPath[_ftcslen(rgchPath)-1] = 0;
_ftcscpy(lpName, rgchBase);
_ftcscat(lpName, _T("."));
_ftcscat(lpName, rgchPath);
} else {
_ftcscpy(lpName, rgchBase);
_ftcscat(lpName, _T(".exe"));
}
}
break;
}
}
MHFree(pT);
break;
}
}
return rVal;
}
LPMODULEALIAS FindAddAliasByModule(LPSTR lpImageName, LPSTR lpModuleName)
/*++
Routine Description:
Look for an alias entry by its "common" name, for example, look for "NT".
If it does not exist, and a new image name has been provided, add it.
If it does exist and a new image name has been provided, replace the image name.
Return the new or found record.
--*/
{
int i;
for (i=0; i<MAX_MODULEALIAS; i++) {
if (ModuleAlias[i].ModuleName[0] == 0) {
if (!lpImageName) {
return NULL;
} else {
_tcscpy( ModuleAlias[i].Alias, lpImageName );
_tcscpy( ModuleAlias[i].ModuleName, lpModuleName );
ModuleAlias[i].Special = 1;
return &ModuleAlias[i];
}
}
if (_tcsicmp( ModuleAlias[i].ModuleName, lpModuleName ) == 0) {
if (lpImageName) {
_tcscpy( ModuleAlias[i].Alias, lpImageName);
}
return &ModuleAlias[i];
}
}
// Should return before here
assert( 0 );
return NULL;
}
LPMODULEALIAS FindAliasByImageName(LPSTR lpImageName)
{
int i;
for (i=0; i<MAX_MODULEALIAS; i++) {
if (ModuleAlias[i].ModuleName[0] == 0) {
return NULL;
}
if (_tcsicmp( ModuleAlias[i].Alias, lpImageName ) == 0) {
return &ModuleAlias[i];
}
}
// Should return before here
assert( 0 );
return NULL;
}
LPMODULEALIAS CheckForRenamedImage(
HPRCX hprc,
LOAD_DLL_DEBUG_INFO64 *ldd,
LPTSTR lpOrigImageName,
LPTSTR lpModuleName
)
{
CHAR ImageName[MAX_PATH];
CHAR fname[_MAX_FNAME];
CHAR ext[_MAX_EXT];
DWORD i;
if (_ftcsicmp( (LPTSTR)ldd->lpImageName, lpOrigImageName ) != 0) {
return NULL;
}
if (GetModnameFromImage( hprc, ldd, ImageName ) && ImageName[0]) {
_splitpath( ImageName, NULL, NULL, fname, ext );
sprintf( ImageName, _T("%s%s"), fname, ext );
return FindAddAliasByModule(ImageName, lpModuleName);
}
return NULL;
}
BOOL
LoadDll(
LPDEBUG_EVENT64 de,
HTHDX hthd,
LPWORD lpcbPacket,
LPBYTE * lplpbPacket,
BOOL fThreadIsStopped
)
/*++
Routine Description:
This routine is used to load the signification information about
a PE exe file. This information consists of the name of the exe
just loaded (hopefully this will be provided later by the OS) and
a description of the sections in the exe file.
Arguments:
de - Supplies a pointer to the current debug event
hthd - Supplies a pointer to the current thread structure
lpcbPacket - Returns the count of bytes in the created packet
lplpbPacket - Returns the pointer to the created packet
fThreadIsStopped - Supplies a flag to tell the shell whether to send a continue
Return Value:
True on success and FALSE on failure
--*/
{
LPLOAD_DLL_DEBUG_INFO64 ldd = &de->u.LoadDll;
LPMODULELOAD lpmdl;
CHAR szModName[MAX_PATH];
DWORD lenSz;
INT iDll;
HPRCX hprc = hthd->hprc;
CHAR fname[_MAX_FNAME];
CHAR ext[_MAX_EXT];
CHAR szFoundName[_MAX_PATH];
LPMODULEALIAS Alias = NULL;
DWORD i;
IMAGEINFO ii;
static int FakeDllNumber = 0;
TCHAR FakeDllName[13];
// extern owned by kdapi.c:
extern DWORD CacheProcessors;
static ULONG64 uMmSystemRangeStart = SE32To64(-1);
ii.TimeStamp = -1;
ii.SizeOfImage = -1;
if ( hprc->pstate & (ps_killed | ps_dead) ) {
// Process is dead, don't bother doing anything.
return FALSE;
}
assert( Is64PtrSE(ldd->lpBaseOfDll) );
if ( *(LPTSTR)ldd->lpImageName == 0 ) {
ldd->lpImageName = (UINT_PTR)FakeDllName;
sprintf(FakeDllName, _T("DLL%05x"), FakeDllNumber++);
}
if (_ftcsicmp( (LPTSTR)ldd->lpImageName, HAL_IMAGE_NAME ) == 0) {
Alias = CheckForRenamedImage( hprc, ldd, HAL_IMAGE_NAME, HAL_MODULE_NAME );
}
if (_ftcsicmp( (LPTSTR)ldd->lpImageName, KERNEL_IMAGE_NAME ) == 0) {
Alias = CheckForRenamedImage( hprc, ldd, KERNEL_IMAGE_NAME, KERNEL_MODULE_NAME );
if (!Alias && CacheProcessors > 1) {
Alias = FindAddAliasByModule( KERNEL_IMAGE_NAME_MP, KERNEL_MODULE_NAME );
}
}
if (!Alias) {
Alias = FindAliasByImageName((LPTSTR)ldd->lpImageName);
}
// Create an entry in the DLL list and set the index to it so that
// we can have information about all DLLs for the current system.
for (iDll=0; iDll<hprc->cDllList; iDll+=1) {
if (!hprc->rgDllList[iDll].fValidDll) {
break;
}
}
if (iDll == hprc->cDllList) {
// the dll list needs to be expanded
hprc->cDllList += 10;
hprc->rgDllList = MHRealloc(hprc->rgDllList,
hprc->cDllList * sizeof(DLLLOAD_ITEM));
memset(&hprc->rgDllList[hprc->cDllList-10], 0, 10*sizeof(DLLLOAD_ITEM));
} else {
memset(&hprc->rgDllList[iDll], 0, sizeof(DLLLOAD_ITEM));
}
assert( Is64PtrSE(ldd->lpBaseOfDll) );
hprc->rgDllList[iDll].fValidDll = TRUE;
hprc->rgDllList[iDll].offBaseOfImage = (OFFSET) ldd->lpBaseOfDll;
assert( Is64PtrSE(hprc->rgDllList[iDll].offBaseOfImage) );
hprc->rgDllList[iDll].cbImage = ldd->dwDebugInfoFileOffset;
if (Alias) {
_splitpath( Alias->ModuleName, NULL, NULL, fname, ext );
} else {
_splitpath( (LPTSTR)ldd->lpImageName, NULL, NULL, fname, ext );
}
hprc->rgDllList[iDll].szDllName = MHAlloc(_ftcslen(fname)+_ftcslen(ext)+4);
sprintf( hprc->rgDllList[iDll].szDllName, _T("%s%s"), fname, ext );
hprc->rgDllList[iDll].NumberOfSections = 0;
hprc->rgDllList[iDll].Sections = NULL;
hprc->rgDllList[iDll].sec = NULL;
*szFoundName = 0;
LoadKdDataBlock();
assert( Is64PtrSE(ldd->lpBaseOfDll) );
if (uMmSystemRangeStart == SE32To64(-1)) {
// Has not yet been initialized
DWORD dwStatus;
ULONG u32;
ULONG64 u64;
assert( Is64PtrSE(KdDebuggerData.MmSystemRangeStart) );
dwStatus = DmKdReadMemoryWrapper(KdDebuggerData.MmSystemRangeStart,
DmKdPtr64 ? (PVOID) &u64 : (PVOID) &u32,
DmKdPtr64 ? sizeof(u64) : sizeof(u32),
NULL
);
if (STATUS_SUCCESS == dwStatus) {
if (DmKdPtr64) {
uMmSystemRangeStart = u64;
} else {
uMmSystemRangeStart = SE32To64(u32);
}
}
}
// Make sure uMmSystemRangeStart is not 0 and that it has been initialized
if (uMmSystemRangeStart
&& uMmSystemRangeStart != SE32To64(-1)
&& ldd->lpBaseOfDll < uMmSystemRangeStart) {
// must be a usermode module
if (ReadImageInfo( hprc->rgDllList[iDll].szDllName,
szFoundName,
(LPSTR)KdOptions[KDO_SYMBOLPATH].value,
&ii )) {
// we found the debug info, so now save the sections
// this data is used by processgetsectionscmd()
hprc->rgDllList[iDll].NumberOfSections = ii.NumberOfSections;
hprc->rgDllList[iDll].sec = ii.Sections;
// Always sign extend, no matter what.
assert( Is64PtrSE(ii.BaseOfImage) );
hprc->rgDllList[iDll].offBaseOfImage = ii.BaseOfImage;
hprc->rgDllList[iDll].cbImage = ii.SizeOfImage;
ldd->hFile = (HANDLE)ii.CheckSum;
}
}
#ifdef TARGET_i386
hprc->rgDllList[iDll].SegCs = (WORD) hthd->context.SegCs;
hprc->rgDllList[iDll].SegDs = (WORD) hthd->context.SegDs;
#endif
// Make up a record to send back from the name.
// Additionally send back:
// The file handle (if local)
// The load base of the dll
// The time and date stamp of the exe
// The checksum of the file
// ... and optionally the string "MP" to signal
// a multi-processor system to the symbol handler
*szModName = CMODULEDEMARCATOR;
// Send the name found by ReadImageInfo if it found an exe; if it
// only found a dbg, send the default name.
_ftcscpy( szModName + 1,
*szFoundName ? szFoundName : hprc->rgDllList[iDll].szDllName);
lenSz=_ftcslen(szModName);
szModName[lenSz] = CMODULEDEMARCATOR;
if (ii.SizeOfImage == -1) {
// Get the image size from LoadDll debug event
ii.SizeOfImage = ldd->dwDebugInfoFileOffset;
}
if (ii.TimeStamp == -1) {
IMAGE_NT_HEADERS64 NtHeaders;
// Get Image timestamp
ii.TimeStamp = hprc->rgDllList[iDll].TimeStamp;
if (!ii.TimeStamp) {
ULONG SizeOfImage;
// Read from NT image header
DbgReadNtHeader(ldd->lpBaseOfDll, &NtHeaders);
switch (NtHeaders.OptionalHeader.Magic)
{
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
SizeOfImage = ((PIMAGE_NT_HEADERS32) &NtHeaders)->OptionalHeader.SizeOfImage;
break;
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
SizeOfImage = NtHeaders.OptionalHeader.SizeOfImage;
break;
}
ii.TimeStamp = (hprc->rgDllList[iDll].TimeStamp = NtHeaders.FileHeader.TimeDateStamp);
ii.SizeOfImage = SizeOfImage;
}
}
sprintf( szModName+lenSz+1,_T("0x%08X%c0x%08X%c0x%016I64X%c0x%016I64X%c0x%08x%c"),
ii.TimeStamp, CMODULEDEMARCATOR, // timestamp
HandleToUlong(ldd->hFile), CMODULEDEMARCATOR, // checksum
(LONG64)-1, CMODULEDEMARCATOR, // File handle
hprc->rgDllList[iDll].offBaseOfImage, CMODULEDEMARCATOR,
ii.SizeOfImage, CMODULEDEMARCATOR
);
if (Alias) {
_ftcscat( szModName, Alias->Alias );
lenSz = _ftcslen(szModName);
szModName[lenSz] = CMODULEDEMARCATOR;
szModName[lenSz+1] = 0;
if (Alias->Special == 2) {
// If it's a one-shot alias, nuke it.
memset(Alias, 0, sizeof(MODULEALIAS));
}
}
lenSz = _ftcslen(szModName);
_ftcsupr(szModName);
// Allocate the packet which will be sent across to the EM.
// The packet will consist of:
// The MDL structure sizeof(MDL) +
// The section description array cobj*sizeof(OBJD) +
// The name of the DLL lenSz+1
*lpcbPacket = (WORD)(sizeof(MODULELOAD) + (lenSz+1));
*lplpbPacket= (LPBYTE)(lpmdl=(LPMODULELOAD)MHAlloc(*lpcbPacket));
ZeroMemory( lpmdl, *lpcbPacket );
lpmdl->lpBaseOfDll = hprc->rgDllList[iDll].offBaseOfImage;
assert( Is64PtrSE(lpmdl->lpBaseOfDll) );
// mark the MDL packet as deferred:
lpmdl->cobj = -1;
lpmdl->mte = (WORD) -1;
#ifdef TARGET_i386
lpmdl->CSSel = (unsigned short)hthd->context.SegCs;
lpmdl->DSSel = (unsigned short)hthd->context.SegDs;
#else
lpmdl->CSSel = lpmdl->DSSel = 0;
#endif
lpmdl->fRealMode = 0;
lpmdl->fFlatMode = 1;
lpmdl->fOffset32 = 1;
lpmdl->dwSizeOfDll = hprc->rgDllList[iDll].cbImage;
lpmdl->fThreadIsStopped = fThreadIsStopped;
// Copy the name of the dll to the end of the packet.
memcpy(((BYTE*)&lpmdl->rgobjd), szModName, lenSz+1);
if (fDisconnected) {
// this will prevent the dm from sending a message up to
// the shell. the dm's data structures are setup just fine
// so that when the debugger re-connects we can deliver the
// mod loads correctly.
return FALSE;
}
return TRUE;
} /* LoadDll() */