/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: halkd.cpp - runtime support for kernel debugging // // For more information see: // \nt\base\ntos\kd64 // \nt\base\boot\kdcom // \nt\base\boot\kd1394 // \nt\base\boot\kdusb2 // \nt\sdktools\debuggers\ntsd64 // // Note: Kernel Only // #include "hal.h" #include "halkd.h" extern "C" void * __cdecl memcpy(void *, const void *, size_t); extern "C" void * __cdecl memset(void *, int, size_t); #define FALSE 0 #define TRUE 1 #define ASSERT(x) #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) // // Debugger Debugging // #define KDDBG if (0) kdprintf #define KDDBG2 if (0) kdprintf #define KDDBG3 if (0) kdprintf #define KeProcessorLevel 15 // // Globals // BOOL KdDebuggerNotPresent = FALSE; BOOL KdAlwaysPrintOutput = FALSE; #define KDP_MESSAGE_BUFFER_SIZE 4096 static CHAR KdpMessageBuffer[KDP_MESSAGE_BUFFER_SIZE]; static BOOL KdpContextSent; static KPROCESSOR_STATE KdpProcessorState[MAX_CPU]; static KD_CONTEXT KdpContext; static int KeNumberProcessors = 1; KDP_BREAKPOINT_TYPE KdpBreakpointInstruction = KDP_BREAKPOINT_VALUE; BREAKPOINT_ENTRY KdpBreakpointTable[BREAKPOINT_TABLE_SIZE] = {0}; // // Some quick macros to avoid having to edit too much NT code // #define RtlZeroMemory(base, len) memset((base), 0, (len)) #define KdpQuickMoveMemory(dst, src, len) memcpy((dst), (src), (len)) // Read memory from an untrusted pointer into a trusted buffer. #define KdpCopyFromPtr(Dst, Src, Size, Done) \ KdpCopyMemoryChunks((ULONG_PTR)(Src), Dst, Size, 0, \ MMDBG_COPY_UNSAFE, Done) // Write memory from a trusted buffer through an untrusted pointer. #define KdpCopyToPtr(Dst, Src, Size, Done) \ KdpCopyMemoryChunks((ULONG_PTR)(Dst), Src, Size, 0, \ MMDBG_COPY_WRITE | MMDBG_COPY_UNSAFE, Done) #define RtlInitUnicodeString(string, source, length) \ { (string)->Buffer = (source); (string)->Length = (string)->MaximumLength = (length); } #define FORCEINLINE __inline void FORCEINLINE InitializeListHead( IN PLIST_ENTRY ListHead ) { ListHead->Flink = ListHead->Blink = ListHead; } BOOLEAN FORCEINLINE RemoveEntryList( IN PLIST_ENTRY Entry ) { PLIST_ENTRY Blink; PLIST_ENTRY Flink; Flink = Entry->Flink; Blink = Entry->Blink; Blink->Flink = Flink; Flink->Blink = Blink; return (BOOLEAN)(Flink == Blink); } void FORCEINLINE InsertTailList( IN PLIST_ENTRY ListHead, IN PLIST_ENTRY Entry ) { PLIST_ENTRY Blink; Blink = ListHead->Blink; Entry->Flink = ListHead; Entry->Blink = Blink; Blink->Flink = Entry; ListHead->Blink = Entry; } //#define KdpCopyFromPtr(dst, src, size, done) { memcpy((dst), (src), (size)); *(done)=(size); } //#define KdpCopyToPtr(dst, src, size, done) { memcpy((dst), (src), (size)); *(done)=(size); } // // KdpRetryCount controls the number of retries before we give // up and assume kernel debugger is not present. // KdpNumberRetries is the number of retries left. Initially, // it is set to 5 such that booting NT without debugger won't be // delayed to long. // UINT32 KdCompNumberRetries = 5; UINT32 KdCompRetryCount = 5; UINT32 KdPacketId = 0; static void KdpNulSendPacket(UINT32 PacketType, IN PSTRING MessageHeader, IN PSTRING MessageData OPTIONAL, IN OUT PKD_CONTEXT KdContext) { } static KDP_STATUS KdpNulReceivePacket(IN UINT32 PacketType, OUT PSTRING MessageHeader, OUT PSTRING MessageData, OUT UINT32 * DataLength, IN OUT PKD_CONTEXT KdContext) { return KDP_PACKET_TIMEOUT; } static bool KdpNulPollBreakIn() { return false; } void (*KdSendPacket)(UINT32 PacketType, IN PSTRING MessageHeader, IN PSTRING MessageData OPTIONAL, IN OUT PKD_CONTEXT KdContext) = KdpNulSendPacket; KDP_STATUS (*KdReceivePacket)(IN UINT32 PacketType, OUT PSTRING MessageHeader, OUT PSTRING MessageData, OUT UINT32 * DataLength, IN OUT PKD_CONTEXT KdContext) = KdpNulReceivePacket; bool (*KdPollBreakIn)() = KdpNulPollBreakIn; // // Static data - these are walked by the kernel debugger // //PsLoadedModuleList =========================================================== struct KLDR_DATA_TABLE_ENTRY_WITH_NAME : KLDR_DATA_TABLE_ENTRY { WCHAR wzName[32]; }; static KLDR_DATA_TABLE_ENTRY_WITH_NAME KdModuleKernelEntry[128]; static UINT32 KdModuleKernelUsed = 0; static LIST_ENTRY PsLoadedModuleList; // KdVersionBlock ============================================================= static DBGKD_GET_VERSION64 KdVersionBlock = { DBGKD_MAJOR_SINGULARITY << 8, // MajorVersion 0, // Minor DBGKD_64BIT_PROTOCOL_VERSION2, // Protocol DBGKD_VERS_FLAG_NOMM, //DBGKD_VERS_FLAG_DATA, // Flags #if ISA_IX86 IMAGE_FILE_MACHINE_X86, // Machine Type #elif ISA_IX64 IMAGE_FILE_MACHINE_X64, // Machine Type #elif ISA_ARM IMAGE_FILE_MACHINE_ARM, // Machine Type #endif PACKET_TYPE_MAX, // Max packet DbgKdMaximumStateChange - DbgKdMinimumStateChange, // MaxStateChange DbgKdSetContextApi /*DbgKdMaximumManipulate*/ - DbgKdMinimumManipulate, // MaxManipulate we support 0, // Simulation 0, // Unused 0, // KernBase 0, // PsLoadedModuleList 0 // DebuggerDataList }; // ======================================================================== // Forward declarations static void KdpMpLock(void); static void KdpMpUnlock(void); static void KdpMpEnter(void); static void KdpMpLeave(void); static void KdpUpLock(void); static void KdpUpUnlock(void); static void KdpUpEnter(void); static void KdpUpLeave(void); static void KdpFakeOutPsLoadedModuleList(Class_Microsoft_Singularity_Hal_Platform *); static KCONTINUE_STATUS KdpSendWaitContinue( IN UINT32 OutPacketType, IN PSTRING OutMessageHeader, IN PSTRING OutMessageData OPTIONAL, IN OUT Struct_Microsoft_Singularity_Isal_SpillContext *Context ); static void LoadedBinary(KdDebugTrapData *trapData, Struct_Microsoft_Singularity_Isal_SpillContext *context); static void UnloadedBinary(KdDebugTrapData *trapData, Struct_Microsoft_Singularity_Isal_SpillContext *context); extern int printf(const char *pszFmt, ...); #if ISA_ARM void (*KdpLock)() = KdpUpLock; void (*KdpUnlock)() = KdpUpUnlock; void (*KdpEnter)() = KdpUpEnter; void (*KdpLeave)() = KdpUpLeave; #else void (*KdpLock)() = KdpMpLock; void (*KdpUnlock)() = KdpMpUnlock; void (*KdpEnter)() = KdpMpEnter; void (*KdpLeave)() = KdpMpLeave; #endif // Ack! We cannot replicate the entire pathway through HAL just so single-stepping // doesn't become nested and confused. static bool KdpDisableInterrupts(void) { return KdpDisableInterruptsInline(); } static void KdpRestoreInterrupts(bool enabled) { return KdpRestoreInterruptsInline(enabled); } ////////////////////////////////////////////////////////////////////////////// // static volatile INT32 KdpInDebugger = 0; static volatile bool KdpInDebuggerIntEnabled = FALSE; // // Sending IPI's to other processors may be broken at times, and // this allows recursive entry to the debugger from breakpoints // or exceptions in the SendIPI code. // static volatile INT32 KdpCpuInDebugger = -1; static volatile INT32 KdpMpEnterCount = 0; static volatile INT32 KdpLockEnterCount = 0; static CHAR KdpDbgMessageBuffer[KDP_MESSAGE_BUFFER_SIZE]; #define MAXIMUM_RETRIES 20 void KdInitialize(Class_Microsoft_Singularity_Hal_Platform *platform) { kdprintf("KdInitialize! [CpuMaxCount=%d]\n", platform->CpuMaxCount); if (platform->CpuMaxCount == 1) { KdpLock = KdpUpLock; KdpUnlock = KdpUpUnlock; KdpEnter = KdpUpEnter; KdpLeave = KdpUpLeave; } else { KdpLock = KdpMpLock; KdpUnlock = KdpMpUnlock; KdpEnter = KdpMpEnter; KdpLeave = KdpMpLeave; } KdpLock(); // // Note that this is not quite right - the Hal debugger routines are only called // if DEBUGGER_SERIAL is configured. The right thing to do is always go through the HAL, // and then do the switching between serial/1394 inside the hal. // @todo: Fix this when reconciling native HAL. // switch (platform->DebuggerType) { default: case Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_NONE: kdprintf("No debugger.\n"); KdSendPacket = KdpNulSendPacket; KdReceivePacket = KdpNulReceivePacket; KdPollBreakIn = KdpNulPollBreakIn; KdDebuggerNotPresent = TRUE; KdAlwaysPrintOutput = TRUE; // do we really want to do this? break; case Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_SERIAL: kdprintf("Serial Debugger:\n"); KdSendPacket = KdpSerialSendPacket; KdReceivePacket = KdpSerialReceivePacket; KdPollBreakIn = KdpSerialPollBreakIn; KdDebuggerNotPresent = FALSE; break; case Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_1394: kdprintf("1394 Debugger:\n"); KdSendPacket = Kdp1394SendPacket; KdReceivePacket = Kdp1394ReceivePacket; KdPollBreakIn = Kdp1394PollBreakIn; KdDebuggerNotPresent = FALSE; break; } // Retries are set to this after boot KdpContext.KdpDefaultRetries = MAXIMUM_RETRIES; KdpUnlock(); KdpFakeOutPsLoadedModuleList(platform); } // // Return current CPU ID // int KdCurrentCpuId() { return Class_Microsoft_Singularity_Isal_Isa::g_GetCurrentCpu()->id; } // // MP-safe versions of lock/unlock enter/leave kd functions // static void KdpMpLock() { for (;;) { bool enabled = KdpDisableInterrupts(); if (InterlockedCompareExchange(&KdpInDebugger, 1, 0) == 0) { KdpInDebuggerIntEnabled = enabled; KdpCpuInDebugger = KdCurrentCpuId(); KdpLockEnterCount++; return; } // Check to see if its already us recursively if (KdpCpuInDebugger == KdCurrentCpuId()) { KdpLockEnterCount++; kdprintf("CPU %d: KdpMpLock: Entered Recursively due to breakpoint or exception, EnterCount %d\n", KdpCpuInDebugger, KdpLockEnterCount); return; } KdpRestoreInterrupts(enabled); KdpPause(); } } static void KdpMpUnlock() { KdpLockEnterCount--; // Recursive lock leave if (KdpLockEnterCount != 0) { return; } // Must grab the state of interrupts before we release our lock. Fortunately, // KdpInDebuggerIntEnabled is volatile, so the compiler will not reorder our // read: bool intEnabled = KdpInDebuggerIntEnabled; KdpCpuInDebugger = -1; KdpInDebugger = 0; KdpRestoreInterrupts(intEnabled); } static void KdpMpEnter() { KdpMpEnterCount++; // Only attempt to stop processors on the first entry if (KdpMpEnterCount == 1) { if (KeNumberProcessors > 1) { KDDBG("CPU %d: KdpMpEnter, calling FreezeAllProcessors...\n", KdCurrentCpuId()); Class_Microsoft_Singularity_MpExecution::g_FreezeAllProcessors(); KDDBG("CPU %d: KdpMpEnter, return from FreezeAllProcessors...\n", KdCurrentCpuId()); } } } static void KdpMpLeave() { KdpMpEnterCount--; Class_Microsoft_Singularity_MpExecution::g_ThawAllProcessors(); } // // Single processor versions of lock/unlock enter/leave kd functions // static void KdpUpLock() { bool enabled = KdpDisableInterrupts(); KdpInDebugger++; if (KdpInDebugger == 1) { KdpInDebuggerIntEnabled = enabled; } } static void KdpUpUnlock() { KdpInDebugger--; if (KdpInDebugger == 0) { KdpRestoreInterrupts(KdpInDebuggerIntEnabled); } } static void KdpUpEnter(void) { } static void KdpUpLeave(void) { } ////////////////////////////////////////////////////////////////////////////// // extern int strformat(void (*pfOutput)(void *pContext, char c), void *pContext, const char * pszFmt, va_list args); static void koutput(void *pContext, char c) { #if ISA_IX86 || ISA_IX64 #define KD_LEFT 0 #define KD_HEIGHT 46 static UINT16 kdcurs = KD_LEFT; static UINT16 kdattr = 0x2f00; // // Update cursor position // if ((kdcurs % 80) < KD_LEFT) { kdcurs += KD_LEFT - (kdcurs % 80); } if (kdcurs >= KD_HEIGHT * 80) { for (UINT16 i = 0; i < KD_HEIGHT - 1; i++) { for (UINT16 j = KD_LEFT; j < 80; j++) { ((UINT16 *)0xb8000)[i*80+j] = ((UINT16 *)0xb8000)[i*80+80+j]; } } for (UINT16 j = KD_LEFT; j < 80; j++) { ((UINT16 *)0xb8000)[(KD_HEIGHT-1)*80+j] = kdattr | ' '; } kdcurs = kdcurs - 80; } // // Output character // if (c >= ' ' && c <= '~') { ((UINT16 *)0xb8000)[kdcurs++] = kdattr | c; } else if (c == '\t') { kdcurs += 8 - (kdcurs % 8); } else if (c == '\n') { while ((kdcurs % 80) != 0) { ((UINT16 *)0xb8000)[kdcurs++] = kdattr | ' '; } } else if (c == '\r') { kdcurs -= (kdcurs % 80); } else if (c == '\f') { kdcurs = 0; } #elif ISA_ARM // Do nothing. #endif } void kdprints(const char * pszFmt) { while (*pszFmt) { koutput(NULL, *pszFmt++); } } void kdprintf(const char * pszFmt, ...) { va_list args; va_start(args, pszFmt); strformat(koutput, NULL, pszFmt, args); va_end(args); } BOOL ProbeMemoryRange(UINT64 address, UINT32 length) { Struct_Microsoft_Singularity_SMAPINFO *sm = (Struct_Microsoft_Singularity_SMAPINFO *)Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->Smap32; int smapCount = Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->SmapCount; for (int32 i = 0; i < smapCount; i++) { if (// (sm[i].type == Struct_Microsoft_Singularity_SMAPINFO_AddressTypeFree) && (sm[i].addr <= address) && (sm[i].addr + sm[i].size) >= (address + length)) { return true; } } if ((address >= Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->Smap32) && ((address + length) <= (Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->Smap32 + 4096))) { return true; } if ((address >= Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogRecordBuffer) && ((address + length) <= (Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogRecordBuffer + Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogRecordSize))) { return true; } if ((address >= Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogTextBuffer) && ((address + length) <= (Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogTextBuffer + Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogTextSize))) { return true; } if ((address >= Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->Smap32) && ((address + length) <= (Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->Smap32 + 4096))) { return true; } if ((address >= Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogRecordBuffer) && ((address + length) <= (Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogRecordBuffer + Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogRecordSize))) { return true; } if ((address >= Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogTextBuffer) && ((address + length) <= (Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogTextBuffer + Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->LogTextSize))) { return true; } #if ISA_IX // TODO: HACK!HACK!HACK! These I/O ranges // should not be hardcoded, but probed and put into the SMAP // as reserved, . const UINT64 ApicBase = 0xfee00000; const UINT32 ApicLength = 0x1000; const UINT64 IoApic0Base = 0xfec00000; const UINT32 IoApicLength = 0x100; const UINT64 IoApic1Base = 0xfec80000; if (address >= ApicBase && address <= ApicBase + ApicLength) { return true; } if (address >= IoApic0Base && address <= IoApic0Base + IoApicLength) { return true; } if (address >= IoApic1Base && address <= IoApic1Base + IoApicLength) { return true; } #endif // // TODO: revisit this with paging and new MM design // #if ISA_ARM KDDBG("ProbeFailed %p..%p\n", (UIntPtr)address, (UIntPtr)(address + length)); #endif return false; } ////////////////////////////////////////////////////////////////////////////// // UINT32 KdpComputeChecksum(IN PCHAR Buffer, IN UINT32 Length) { // Compute the checksum for the string passed in. UINT32 Checksum = 0; while (Length > 0) { Checksum = Checksum + (UINT32)*(PUCHAR)Buffer++; Length--; } return(Checksum); } // KdpComputeChecksum ////////////////////////////////////////////////////////////////////////////// // UINT16 KdpGetCurrentProcessorNumber() { return (UINT16) Class_Microsoft_Singularity_Isal_Isa::g_GetCurrentCpu()->id; } // KdpGetCurrentProcessorNumber ////////////////////////////////////////////////////////////////////////////// // // Misc KD functions // NTSTATUS KdpCopyMemoryChunks( UINT64 Address, PVOID Buffer, UINT32 TotalSize, UINT32 ChunkSize, UINT32 Flags, UINT32 * ActualSize OPTIONAL ) // Routine Description: // Copies memory to/from a buffer to/from a system address. // The address can be physical or virtual. // The buffer is assumed to be valid for the duration of this call. // // Arguments: // Address - System address. // Buffer - Buffer to read from or write to. // TotalSize - Number of bytes to read/write. // ChunkSize - Maximum single item transfer size, must // be 1, 2, 4 or 8. // 0 means choose a default. // Flags - MMDBG_COPY flags for MmDbgCopyMemory. // ActualSize - Number of bytes actually read/written. { UINT32 Length; UINT32 CopyChunk; if (ChunkSize > MMDBG_COPY_MAX_SIZE) { ChunkSize = MMDBG_COPY_MAX_SIZE; } else if (ChunkSize == 0) { // Default to 4 byte chunks as that's // what the previous code did. ChunkSize = 4; } // // MmDbgCopyMemory only copies a single aligned chunk at a // time. It is Kd's responsibility to chunk up a larger // request for individual copy requests. This gives Kd // the flexibility to pick a chunk size and also frees // Mm from having to worry about more than a page at a time. // Additionally, it is important that we access memory with the // largest size possible because we could be accessing // memory-mapped I/O space. // Length = TotalSize; CopyChunk = 1; while (Length > 0) { // Expand the chunk size as long as: // We haven't hit the chunk limit. // We have enough data left. // The address is properly aligned. while (CopyChunk < ChunkSize && (CopyChunk << 1) <= Length && (Address & ((CopyChunk << 1) - 1)) == 0) { CopyChunk <<= 1; } // Shrink the chunk size to fit the available data. while (CopyChunk > Length) { CopyChunk >>= 1; } if (Address < Class_Microsoft_Singularity_Hal_Platform::c_thePlatform->PhysicalBase) { break; } if (Address == 0) { break; } #if PAGING UINT64 RawAddress = Address; if (Flags & MMDBG_COPY_PHYSICAL) { // Temporarily map the physical memory range. // TODO: KernelMapPhysicalMemory tries to acquire a lock -- if // this lock is not free, we may deadlock here. // Also, remapping for every chunk is inefficient. KDDBG("Physical address = 0x%x size = 0x%x\n", int(Address), int(CopyChunk)); Struct_Microsoft_Singularity_Memory_PhysicalAddress physical; Struct_Microsoft_Singularity_Memory_PhysicalAddress::m__ctor( &physical, UIntPtr(Address)); Address = UINT64(Class_Microsoft_Singularity_Memory_MemoryManager ::g_KernelMapPhysicalMemory( physical, UIntPtr(CopyChunk))); KDDBG("Physical address 0x%x mapped to virtual address 0x%x\n", int(RawAddress), int(Address)); } else { if (Class_Microsoft_Singularity_Memory_MemoryManager::c_isInitialized && !Class_Microsoft_Singularity_Memory_VMManager::g_IsPageMapped( Class_Microsoft_Singularity_Memory_MemoryManager::g_PageAlign( UIntPtr(Address)))) { break; } } #endif // // It is illegal to just touch the memory that the debugger just asked for // w/o making sure it is valid. Otherwise this will trap inside the debugger // code, hanging both the system and debugger. We need to ansure the memory // is valid. For now just check against the smap. // if (!ProbeMemoryRange(Address, CopyChunk)) { break; } if (Flags & MMDBG_COPY_WRITE) { memcpy((void*)Address, Buffer, CopyChunk); } else { memcpy(Buffer, (void*)Address, CopyChunk); } #if PAGING if (Flags & MMDBG_COPY_PHYSICAL) { KDDBG("Unmapping physical address 0x%x (virtual address 0x%x)\n", int(RawAddress), int(Address)); Class_Microsoft_Singularity_Memory_MemoryManager ::g_KernelUnmapPhysicalMemory( UIntPtr(Address), UIntPtr(Address + CopyChunk)); KDDBG("Unmapped physical address 0x%x (virtual address 0x%x)\n", int(RawAddress), int(Address)); Address = RawAddress; } #endif Address += CopyChunk; Buffer = (PVOID)((PUCHAR)Buffer + CopyChunk); Length -= CopyChunk; } if (ActualSize) { *ActualSize = TotalSize - Length; } // // Flush the instruction cache in case the write was into the instruction // stream. Only do this when writing into the kernel address space, // and if any bytes were actually written // if ((Flags & MMDBG_COPY_WRITE) && Length < TotalSize) { KdpFlushInstCache(); } return Length != 0 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS; } static void KdpSetCommonState( IN UINT32 NewState, IN Struct_Microsoft_Singularity_Isal_SpillContext *Context, OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange ) { UINT32 InstrCount; PUCHAR InstrStream; WaitStateChange->NewState = NewState; WaitStateChange->ProcessorLevel = KeProcessorLevel; WaitStateChange->Processor = KdpGetCurrentProcessorNumber(); WaitStateChange->NumberProcessors = KeNumberProcessors; WaitStateChange->Thread = SIGN_EXTEND(Class_Microsoft_Singularity_Processor::g_GetCurrentThreadContext()->_thread); #if ISA_IX86 WaitStateChange->ProgramCounter = SIGN_EXTEND(Context->ip); #elif ISA_IX64 WaitStateChange->ProgramCounter = Context->ip; #elif ISA_ARM WaitStateChange->ProgramCounter = SIGN_EXTEND(Context->pc); #endif RtlZeroMemory(&WaitStateChange->AnyControlReport, sizeof(WaitStateChange->AnyControlReport)); // // Copy instruction stream immediately following location of event. // PCHAR PcMemory = (PCHAR)WaitStateChange->ProgramCounter; InstrStream = (PUCHAR)&WaitStateChange->ControlReport.InstructionStream; KdpCopyFromPtr(InstrStream, PcMemory, sizeof(WaitStateChange->ControlReport.InstructionStream), &InstrCount); WaitStateChange->ControlReport.InstructionCount = (UINT16)InstrCount; // // Clear breakpoints in copied area. // If there were any breakpoints cleared, recopy the instruction area // without them. // // if (KdpDeleteBreakpointRange(PcMemory, PcMemory + InstrCount - 1)) { // KdpCopyFromPtr(InstrStream, PcMemory, InstrCount, &InstrCount); // } } UINT32 WcsToStr(WCHAR *pwcsSrc, UINT32 Length, PCHAR pszDst) { for (UINT32 n = 0; n < Length; n++) { *pszDst++ = (char)*pwcsSrc++; } *pszDst++ = '\0'; return Length + 1; } bool KdpReportLoadSymbolsStateChange( IN WCHAR *PathName, IN UINT32 PathNameLength, IN UINT64 BaseOfDll, IN UINT32 ProcessId, IN UINT32 CheckSum, IN UINT32 SizeOfImage, IN BOOLEAN UnloadSymbols, IN OUT Struct_Microsoft_Singularity_Isal_SpillContext *Context ) // Routine Description: // This routine sends a load symbols state change packet to the kernel // debugger and waits for a manipulate state message. // // Arguments: // PathName - Supplies a pointer to the pathname of the image whose // symbols are to be loaded. // BaseOfDll - Supplies the base address where the image was loaded. // ProcessId - Unique identifier for process that is using // the symbols. -1 for system process. // CheckSum - Checksum from image header. // UnloadSymbol - TRUE if the symbols that were previously loaded for // the named image are to be unloaded from the debugger. { // NB: \nt\sdktools\debuggers\ntsd64\event.cpp // PathNameLength = 0, ProcessId = 0, BaseOfDll = -1 for reboot. // PathNameLength = 0, ProcessId = 0, BaseOfDll = -2 for hibernate. STRING MessageData; STRING MessageHeader; DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange; KCONTINUE_STATUS Status; KDDBG("KdpReportLoadSymbolsStateChange %p\n", Context); do { // // Construct the wait state change message and message descriptor. // KdpSetCommonState(DbgKdLoadSymbolsStateChange, Context, &WaitStateChange); WaitStateChange.LoadSymbols.UnloadSymbols = UnloadSymbols; WaitStateChange.LoadSymbols.BaseOfDll = SIGN_EXTEND(BaseOfDll); WaitStateChange.LoadSymbols.ProcessId = ProcessId; WaitStateChange.LoadSymbols.CheckSum = CheckSum; WaitStateChange.LoadSymbols.SizeOfImage = SizeOfImage; if (PathName != NULL) { WaitStateChange.LoadSymbols.PathNameLength = WcsToStr(PathName, PathNameLength, KdpMessageBuffer); } else { WaitStateChange.LoadSymbols.PathNameLength = 0; } MessageData.Buffer = KdpMessageBuffer; MessageData.Length = (UINT16)WaitStateChange.LoadSymbols.PathNameLength; KdpSetControlReport(&WaitStateChange.ControlReport, Context); MessageHeader.Length = sizeof(WaitStateChange); MessageHeader.Buffer = (PCHAR)&WaitStateChange; Status = KdpSendWaitContinue( PACKET_TYPE_KD_STATE_CHANGE64, &MessageHeader, &MessageData, Context ); } while (Status == ContinueProcessorReselected) ; return (Status == ContinueSuccess) ? true : false; } static KCONTINUE_STATUS KdpReportExceptionStateChange( IN EXCEPTION_RECORD64 *ExceptionRecord, IN OUT Struct_Microsoft_Singularity_Isal_SpillContext *Context, IN BOOLEAN FirstChance ) // Routine Description: // This routine sends an exception state change packet to the kernel // debugger and waits for a manipulate state message. // // Arguments: // ExceptionRecord - Supplies a pointer to an exception record. // Context - Supplies a pointer to a context record. // FirstChance - Supplies a boolean value that determines whether this is // the first or second chance for the exception. // // Return Value: // A value of TRUE is returned if the exception is handled. Otherwise, a // value of FALSE is returned. { STRING MessageData; STRING MessageHeader; DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange; KCONTINUE_STATUS Status; KDDBG("KdpReportExceptionStateChange %p\n", Context); do { // // Construct the wait state change message and message descriptor. // KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange); WaitStateChange.Exception.ExceptionRecord = *ExceptionRecord; WaitStateChange.Exception.FirstChance = FirstChance; KdpSetControlReport(&WaitStateChange.ControlReport, Context); MessageHeader.Length = sizeof(WaitStateChange); MessageHeader.Buffer = (PCHAR)&WaitStateChange; MessageData.Length = 0; // // Send packet to the kernel debugger on the host machine, // wait for answer. // Status = KdpSendWaitContinue( PACKET_TYPE_KD_STATE_CHANGE64, &MessageHeader, &MessageData, Context ); } while (Status == ContinueProcessorReselected) ; return Status; } static void KdpReadVirtualMemory( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData ) // Routine Description: // This function is called in response to a read virtual memory 32-bit // state manipulation message. Its function is to read virtual memory // and return. // // Arguments: // m - Supplies a pointer to the state manipulation message. // AdditionalData - Supplies a pointer to a descriptor for the data to read. { UINT32 Length; STRING MessageHeader; // // Trim the transfer count to fit in a single message. // Length = m->ReadMemory.TransferCount; if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) { Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64); } // // Move the data to the destination buffer. // m->ReturnStatus = KdpCopyMemoryChunks((UINT64)(ULONG_PTR)m->ReadMemory.TargetBaseAddress, AdditionalData->Buffer, Length, 0, MMDBG_COPY_UNSAFE, &Length); // // Set the actual number of bytes read, initialize the message header, // and send the reply packet to the host debugger. // AdditionalData->Length = (UINT16)Length; m->ReadMemory.ActualBytesRead = Length; MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)m; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, AdditionalData, &KdpContext); return; } static void KdpWriteVirtualMemory( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData ) // Routine Description: // This function is called in response of a write virtual memory 32-bit // state manipulation message. Its function is to write virtual memory // and return. // // Arguments: // m - Supplies a pointer to the state manipulation message. // AdditionalData - Supplies a pointer to a descriptor for the data to write. // Context - Supplies a pointer to the current context. { STRING MessageHeader; // // Move the data to the destination buffer. // m->ReturnStatus = KdpCopyMemoryChunks((UINT64)(ULONG_PTR)m->WriteMemory.TargetBaseAddress, AdditionalData->Buffer, AdditionalData->Length, 0, MMDBG_COPY_WRITE | MMDBG_COPY_UNSAFE, &m->WriteMemory.ActualBytesWritten); // // Set the actual number of bytes written, initialize the message header, // and send the reply packet to the host debugger. // MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)m; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); return; } static void KdpReadPhysicalMemory( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData ) // Routine Description: // This function is called in response to a read physical memory 32-bit // state manipulation message. Its function is to read physical memory // and return. // // Arguments: // m - Supplies a pointer to the state manipulation message. // AdditionalData - Supplies a pointer to a descriptor for the data to read. // Context - Supplies a pointer to the current context. { UINT32 Length; STRING MessageHeader; // // Trim the transfer count to fit in a single message. // Length = m->ReadMemory.TransferCount; if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) { Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64); } m->ReturnStatus = KdpCopyMemoryChunks((UINT64)(ULONG_PTR)m->ReadMemory.TargetBaseAddress, AdditionalData->Buffer, Length, 0, MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL, &Length); // // Set the actual number of bytes read, initialize the message header, // and send the reply packet to the host debugger. // AdditionalData->Length = (UINT16)Length; m->ReadMemory.ActualBytesRead = Length; MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)m; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, AdditionalData, &KdpContext); return; } static void KdpWritePhysicalMemory( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData ) // Routine Description: // This function is called in response of a write physical memory 32-bit // state manipulation message. Its function is to write physical memory // and return. // // Arguments: // m - Supplies a pointer to the state manipulation message. // AdditionalData - Supplies a pointer to a descriptor for the data to write. // Context - Supplies a pointer to the current context. { STRING MessageHeader; // // Move the data to the destination buffer. // m->ReturnStatus = KdpCopyMemoryChunks((UINT64)(ULONG_PTR)m->WriteMemory.TargetBaseAddress, AdditionalData->Buffer, AdditionalData->Length, 0, MMDBG_COPY_WRITE | MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL, &m->WriteMemory.ActualBytesWritten); // // Set the actual number of bytes written, initialize the message header, // and send the reply packet to the host debugger. // MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)m; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); return; } static void KdpReadMachineSpecificRegister( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData, IN Struct_Microsoft_Singularity_Isal_SpillContext *Context ) // Routine Description: // This function is called in response of a write physical memory 32-bit // state manipulation message. Its function is to write physical memory // and return. // // Arguments: // m - Supplies a pointer to the state manipulation message. // AdditionalData - Supplies a pointer to a descriptor for the data to write. // Context - Supplies a pointer to the current context. { STRING MessageHeader; // // Read the MSR // m->ReturnStatus = KdpReadMsr(m->ReadWriteMsr.Msr, &m->ReadWriteMsr.DataValueLow, &m->ReadWriteMsr.DataValueHigh) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; // // Set the actual number of bytes written, initialize the message header, // and send the reply packet to the host debugger. // MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)m; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); } static void KdpWriteMachineSpecificRegister( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData, IN Struct_Microsoft_Singularity_Isal_SpillContext *Context ) // Routine Description: // This function is called in response of a write physical memory 32-bit // state manipulation message. Its function is to write physical memory // and return. // // Arguments: // m - Supplies a pointer to the state manipulation message. // AdditionalData - Supplies a pointer to a descriptor for the data to write. // Context - Supplies a pointer to the current context. { STRING MessageHeader; // // Write the MSR // m->ReturnStatus = KdpWriteMsr(m->ReadWriteMsr.Msr, m->ReadWriteMsr.DataValueLow, m->ReadWriteMsr.DataValueHigh) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; // // Set the actual number of bytes written, initialize the message header, // and send the reply packet to the host debugger. // MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)m; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); return; } static int wcslen(WCHAR *pwz) { int len = 0; while (*pwz++) { len++; } return len; } static WCHAR * trim(WCHAR *pwz) { WCHAR *pwzBeg = pwz; for (; *pwz; pwz++) { if (*pwz == '\\') { pwzBeg = pwz + 1; } } return pwzBeg; } KLDR_DATA_TABLE_ENTRY_WITH_NAME KernelEntry; KLDR_DATA_TABLE_ENTRY_WITH_NAME HalEntry; static void KdpFakeOutPsLoadedModuleList(Class_Microsoft_Singularity_Hal_Platform *platform) { // // If the debug information has not been filled in by the loader // we need to reconstruct the loader list from the bootinfo data, // including the hal and the kernel modules // KdVersionBlock.PsLoadedModuleList = SIGN_EXTEND(&PsLoadedModuleList); KdVersionBlock.KernBase = SIGN_EXTEND(platform->KernelDllBase); KernelEntry.DllBase = (void *) platform->KernelDllBase; KernelEntry.CheckSum = 0; KernelEntry.TimeDateStamp = 0; KernelEntry.LoadCount = 1; KernelEntry.SizeOfImage = (uint32)platform->KernelDllSize; #if ISA_IX86 memcpy(KernelEntry.wzName, L"kernel.x86", sizeof(KernelEntry.wzName)); #elif ISA_IX64 memcpy(KernelEntry.wzName, L"kernel.x64", sizeof(KernelEntry.wzName)); #elif ISA_ARM memcpy(KernelEntry.wzName, L"kernel.arm", sizeof(KernelEntry.wzName)); #endif RtlInitUnicodeString(&KernelEntry.BaseDllName, KernelEntry.wzName, 20); RtlInitUnicodeString(&KernelEntry.FullDllName, KernelEntry.wzName, 20); InitializeListHead(&PsLoadedModuleList); InsertTailList(&PsLoadedModuleList, &KernelEntry.InLoadOrderLinks); } void KdpSysGetVersion( PDBGKD_GET_VERSION64 Version ) // Routine Description: // This function returns to the caller a general information packet // that contains useful information to a debugger. This packet is also // used for a debugger to determine if the writebreakpointex and // readbreakpointex APIs are available. // // Arguments: // Version - Supplies the structure to fill in { *Version = KdVersionBlock; } static void KdpGetVersion( IN PDBGKD_MANIPULATE_STATE64 m ) // Routine Description: // This function returns to the caller a general information packet // that contains useful information to a debugger. This packet is also // used for a debugger to determine if the writebreakpointex and // readbreakpointex APIs are available. // // Arguments: // m - Supplies the state manipulation message. { STRING messageHeader; messageHeader.Length = sizeof(*m); messageHeader.Buffer = (PCHAR)m; KdpSysGetVersion(&m->GetVersion64); // // the usual stuff // m->ReturnStatus = STATUS_SUCCESS; m->ApiNumber = DbgKdGetVersionApi; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &messageHeader, NULL, &KdpContext ); return; } // KdGetVersion static inline UINT32 min(UINT32 a, UINT32 b) { return a < b ? a : b; } static void KdpReadControlSpace( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData, IN Struct_Microsoft_Singularity_Isal_SpillContext * Context ) // Routine Description: // This function is called in response of a read control space state // manipulation message. Its function is to read implementation // specific system data. // // Arguments: // m - Supplies the state manipulation message. // AdditionalData - Supplies any additional data for the message. // Context - Supplies the current context. { PDBGKD_READ_MEMORY64 a = &m->ReadMemory; STRING MessageHeader; PVOID Source = NULL; UINT32 Length = 0; UINT32 Actual = 0; UINT32 Isa = (UINT32)a->TargetBaseAddress; MessageHeader.Length = sizeof(*m); MessageHeader.Buffer = (PCHAR)m; ASSERT(AdditionalData->Length == 0); KDDBG2(" rctl base=%x, len=%x\n", Isa, a->TransferCount); if (m->Processor < (UINT32)KeNumberProcessors) { PKPROCESSOR_STATE ProcessorState = &KdpProcessorState[m->Processor]; switch (Isa) { case X86_DEBUG_CONTROL_SPACE_KSPECIAL: case DEBUG_CONTROL_SPACE_KSPECIAL: KdpReadSpecialRegisters(&ProcessorState->SpecialRegisters, Context); Source = &ProcessorState->SpecialRegisters; Length = sizeof(ProcessorState->SpecialRegisters); break; } if (Source != NULL) { if (Length > a->TransferCount) { Length = a->TransferCount; } m->ReturnStatus = KdpCopyToPtr(AdditionalData->Buffer, Source, Length, &Actual); KDDBG2(" rctl: copy src=%p, len=%x, Actual=%x, return status=%x\n", Source, Length, Actual, m->ReturnStatus); } } else { KDDBG("ReadControl: proc %d unknown control type (%d)\n", m->Processor, Isa); m->ReturnStatus = STATUS_UNSUCCESSFUL; } AdditionalData->Length = (UINT16)Actual; a->ActualBytesRead = Actual; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, AdditionalData, &KdpContext); } static void KdpWriteControlSpace( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData, IN Struct_Microsoft_Singularity_Isal_SpillContext * Context ) // Routine Description: // This function is called in response of a write control space state // manipulation message. Its function is to write implementation // specific system data. // // Arguments: // m - Supplies the state manipulation message. // AdditionalData - Supplies any additional data for the message. // Context - Supplies the current context. { PDBGKD_WRITE_MEMORY64 a = &m->WriteMemory; STRING MessageHeader; PVOID Dest = NULL; // Pointer to bytes available to target. UINT32 Length = 0; // # of bytes available to target. UINT32 Isa = (UINT32)a->TargetBaseAddress; PKPROCESSOR_STATE ProcessorState = NULL; MessageHeader.Length = sizeof(*m); MessageHeader.Buffer = (PCHAR)m; KDDBG2(" wctl base=%x, len=%x\n", Isa, a->TransferCount); if (m->Processor < (UINT32)KeNumberProcessors) { ProcessorState = &KdpProcessorState[m->Processor]; switch (Isa) { case X86_DEBUG_CONTROL_SPACE_KSPECIAL: case DEBUG_CONTROL_SPACE_KSPECIAL: Dest = &ProcessorState->SpecialRegisters; Length = sizeof(ProcessorState->SpecialRegisters); break; } } UINT32 Actual = 0; if (Dest != NULL) { if (Length > a->TransferCount) { Length = a->TransferCount; } m->ReturnStatus = KdpCopyToPtr(Dest, AdditionalData->Buffer, Length, &Actual); switch (Isa) { case X86_DEBUG_CONTROL_SPACE_KSPECIAL: case DEBUG_CONTROL_SPACE_KSPECIAL: KdpWriteSpecialRegisters(&ProcessorState->SpecialRegisters); break; } KDDBG2(" wctl: copy dst=%p, len=%x, Actual=%x, return status=%x\n", Dest, Length, Actual, m->ReturnStatus); } else { KDDBG("WriteControl: proc %d unknown control type (%d)\n", m->Processor, Isa); m->ReturnStatus = STATUS_UNSUCCESSFUL; } a->ActualBytesWritten = Actual; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, AdditionalData, &KdpContext); } static void KdpReadIoSpace( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData, IN Struct_Microsoft_Singularity_Isal_SpillContext * x86Context ) // Routine Description: // This function is called in response of a read I/O space // manipulation message. Its function is to read the x86 processors // I/O space and return the result. // // Arguments: // m - Supplies the state manipulation message. // AdditionalData - Supplies any additional data for the message. // Context - Supplies the current context. { PDBGKD_READ_WRITE_IO64 a = &m->ReadWriteIo; STRING MessageHeader; UINT16 Target = (UINT16)a->IoAddress; ASSERT(AdditionalData->Length == 0); KDDBG(" read io base=%x, len=%x\n", Target, a->DataSize, AdditionalData->Buffer); // // Zero-fill the entire value so that shorter reads // do not leave unset bytes. // a->DataValue = 0; m->ReturnStatus = STATUS_SUCCESS; switch (a->DataSize) { case 1: a->DataValue = KdpReadWriteIoSpace(a->DataSize, 0, Target, 0); break; case 2: a->DataValue = KdpReadWriteIoSpace(a->DataSize, 0, Target, 0); break; case 4: a->DataValue = KdpReadWriteIoSpace(a->DataSize, 0, Target, 0); break; default: KDDBG("ReadIoSpace: Unrecognized size (%d)\n", a->DataSize); m->ReturnStatus = STATUS_UNSUCCESSFUL; break; } // // Send the response // MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)m; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); } static void KdpWriteIoSpace( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData, IN Struct_Microsoft_Singularity_Isal_SpillContext * x86Context ) // Routine Description: // This function is called in response of a write I/O space // manipulation message. Its function is to write the x86 processors // I/O space. // // Arguments: // m - Supplies the state manipulation message. // AdditionalData - Supplies any additional data for the message. // Context - Supplies the current context. { PDBGKD_READ_WRITE_IO64 a = &m->ReadWriteIo; STRING MessageHeader; UINT16 Target = (UINT16)a->IoAddress; ASSERT(AdditionalData->Length == 0); KDDBG(" write io base=%x, len=%x, value=%x\n", Target, a->DataSize, a->DataValue); m->ReturnStatus = STATUS_SUCCESS; switch (a->DataSize) { case 1: KdpReadWriteIoSpace(a->DataSize, 1, Target, a->DataValue & 0x000000FF); break; case 2: KdpReadWriteIoSpace(a->DataSize, 1, Target, a->DataValue & 0x0000FFFF); break; case 4: KdpReadWriteIoSpace(a->DataSize, 1, Target, a->DataValue); break; default: KDDBG("WriteIoSpace: Unrecognized size (%d)\n", a->DataSize); m->ReturnStatus = STATUS_UNSUCCESSFUL; break; } // Send the reply MessageHeader.Length = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)m; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); } static void KdpSetContext( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData, IN Struct_Microsoft_Singularity_Isal_SpillContext * Context ) // Routine Description: // This function is called in response of a set context state // manipulation message. Its function is set the current // context. // // Arguments: // m - Supplies the state manipulation message. // AdditionalData - Supplies any additional data for the message. // Context - Supplies the current context. { STRING MessageHeader; MessageHeader.Length = sizeof(*m); MessageHeader.Buffer = (PCHAR)m; ASSERT(AdditionalData->Length == sizeof(CONTEXT)); if ((m->Processor >= (UINT16)KeNumberProcessors) || (KdpContextSent == FALSE)) { m->ReturnStatus = STATUS_UNSUCCESSFUL; } else { m->ReturnStatus = STATUS_SUCCESS; KdpFromKdContext((CONTEXT*)AdditionalData->Buffer, Context); } KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); } static void KdpGetContext( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData, IN Struct_Microsoft_Singularity_Isal_SpillContext *Context ) // Routine Description: // This function is called in response of a get context state // manipulation message. Its function is to return the current // context. // // Arguments: // m - Supplies the state manipulation message. // AdditionalData - Supplies any additional data for the message. // Context - Supplies the current context. { STRING MessageHeader; MessageHeader.Length = sizeof(*m); MessageHeader.Buffer = (PCHAR)m; ASSERT(AdditionalData->Length == 0); if (m->Processor >= (UINT16)KeNumberProcessors) { m->ReturnStatus = STATUS_UNSUCCESSFUL; } else { m->ReturnStatus = STATUS_SUCCESS; AdditionalData->Length = sizeof(CONTEXT); RtlZeroMemory(AdditionalData->Buffer, AdditionalData->Length); KdpToKdContext(Context, (CONTEXT*)AdditionalData->Buffer); KdpContextSent = TRUE; } KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, AdditionalData, &KdpContext); } UINT32 KdpAddBreakpoint( IN PVOID Address ) // Routine Description: // This routine adds an entry to the breakpoint table and returns a handle // to the breakpoint table entry. // // Arguments: // Address - Supplies the address where to set the breakpoint. // // Return Value: // // A value of zero is returned if the specified address is already in the // breakpoint table, there are no free entries in the breakpoint table, the // specified address is not correctly aligned, or the specified address is // not valid. Otherwise, the index of the assigned breakpoint table entry // plus one is returned as the function value. { UINT32 Index; KDP_BREAKPOINT_TYPE Content; BOOL Accessible; KDDBG2("KdpAddBreakpoint(%p)\n", Address); for (Index = 0; Index < BREAKPOINT_TABLE_SIZE; Index++) { if (KdpBreakpointTable[Index].Flags == 0) { break; } } if (Index == BREAKPOINT_TABLE_SIZE) { KDDBG("KD: ran out of breakpoints!\n"); return 0; } Accessible = NT_SUCCESS(KdpCopyFromPtr(&Content, Address, sizeof(KDP_BREAKPOINT_TYPE), NULL)); KDDBG("KD: memory %saccessible\n", Accessible ? "" : "in"); if (Accessible) { KdpBreakpointTable[Index].Address = Address; KdpBreakpointTable[Index].Content = Content; KdpBreakpointTable[Index].Flags = KD_BREAKPOINT_IN_USE; if (!NT_SUCCESS(KdpCopyToPtr(Address, &KdpBreakpointInstruction, sizeof(KDP_BREAKPOINT_TYPE), NULL))) { KDDBG("KD: Unable to write BP!\n"); } } else { return 0; } return Index+1; } BOOLEAN KdpDeleteBreakpoint( IN UINT32 Handle ) { UINT32 Index = Handle - 1; KDDBG2("KD: Delete Breakpoint %d\n", Handle); if ((Handle == 0) || (Handle > BREAKPOINT_TABLE_SIZE)) { KDDBG("KD: Breakpoint %d invalid.\n", Index); return FALSE; } // // Replace the instruction contents. // if (!NT_SUCCESS(KdpCopyToPtr(KdpBreakpointTable[Index].Address, &KdpBreakpointTable[Index].Content, sizeof(KDP_BREAKPOINT_TYPE), NULL))) { KDDBG("KD: Breakpoint at 0x%p; unable to clear, flag set.\n", KdpBreakpointTable[Index].Address); return FALSE; } else { KDDBG2("KD: Breakpoint at 0x%p cleared.\n", KdpBreakpointTable[Index].Address); KdpBreakpointTable[Index].Flags = 0; } return TRUE; } void KdpWriteBreakpoint( IN PDBGKD_MANIPULATE_STATE64 m ) // Routine Description: // This function is called in response of a write breakpoint state // manipulation message. Its function is to write a breakpoint // and return a handle to the breakpoint. // // Arguments: // m - Supplies the state manipulation message. // AdditionalData - Supplies any additional data for the message. // Context - Supplies the current context. { PDBGKD_WRITE_BREAKPOINT64 a = &m->WriteBreakPoint; STRING MessageHeader; MessageHeader.Length = sizeof(*m); MessageHeader.Buffer = (PCHAR)m; ASSERT(AdditionalData->Length == 0); a->BreakPointHandle = KdpAddBreakpoint((PVOID)(ULONG_PTR)a->BreakPointAddress); if (a->BreakPointHandle != 0) { m->ReturnStatus = STATUS_SUCCESS; } else { m->ReturnStatus = STATUS_UNSUCCESSFUL; } KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); } void KdpRestoreBreakpoint( IN PDBGKD_MANIPULATE_STATE64 m, IN PSTRING AdditionalData ) // Routine Description: // This function is called in response of a restore breakpoint state // manipulation message. Its function is to restore a breakpoint // using the specified handle. // // Arguments: // m - Supplies the state manipulation message. // AdditionalData - Supplies any additional data for the message. // Context - Supplies the current context. { PDBGKD_RESTORE_BREAKPOINT a = &m->RestoreBreakPoint; STRING MessageHeader; MessageHeader.Length = sizeof(*m); MessageHeader.Buffer = (PCHAR)m; ASSERT(AdditionalData->Length == 0); if (KdpDeleteBreakpoint(a->BreakPointHandle)) { m->ReturnStatus = STATUS_SUCCESS; } else { m->ReturnStatus = STATUS_UNSUCCESSFUL; } KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, NULL, &KdpContext); } static void KdpGetStateChange( IN PDBGKD_MANIPULATE_STATE64 ManipulateState, IN Struct_Microsoft_Singularity_Isal_SpillContext *Context ) // Routine Description: // Extract continuation control data from Manipulate_State message // // Arguments: // ManipulateState - supplies pointer to Manipulate_State packet // Context - Supplies a pointer to a context record. { if (NT_SUCCESS(ManipulateState->Continue2.ContinueStatus)) { // // If NT_SUCCESS returns TRUE, then the debugger is doing a // continue, and it makes sense to apply control changes. // Otherwise the debugger is saying that it doesn't know what // to do with this exception, so control values are ignored. // KdpSetControlSet(&ManipulateState->Continue2.ControlSet, Context); #if 0 for (Processor = 0; Processor < (UINT32)KeNumberProcessors; Processor++) { Prcb = KiProcessorBlock[Processor]; Prcb->ProcessorState.SpecialRegisters.KernelDr7 = ManipulateState->Continue2.ControlSet.Dr7; Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0L; } if (ManipulateState->Continue2.ControlSet.CurrentSymbolStart != 1) { KdpCurrentSymbolStart = ManipulateState->Continue2.ControlSet.CurrentSymbolStart; KdpCurrentSymbolEnd = ManipulateState->Continue2.ControlSet.CurrentSymbolEnd; } #endif } } KCONTINUE_STATUS KdpSendWaitContinue( IN UINT32 OutPacketType, IN PSTRING OutMessageHeader, IN PSTRING OutMessageData OPTIONAL, IN OUT Struct_Microsoft_Singularity_Isal_SpillContext *Context ) // Routine Description: // This function sends a packet, and then waits for a continue message. // BreakIns received while waiting will always cause a resend of the // packet originally sent out. While waiting, manipulate messages // will be serviced. // A resend always resends the original event sent to the debugger, // not the last response to some debugger command. // // Arguments: // OutPacketType - Supplies the type of packet to send. // OutMessageHeader - Supplies a pointer to a string descriptor that describes // the message information. // OutMessageData - Supplies a pointer to a string descriptor that describes // the optional message data. // x86Record - Exception context // // Return Value: // A value of TRUE is returned if the continue message indicates // success, Otherwise, a value of FALSE is returned. { UINT32 Length; STRING MessageData; STRING MessageHeader; DBGKD_MANIPULATE_STATE64 ManipulateState; UINT32 ReturnCode; // NTSTATUS Status; // KCONTINUE_STATUS ContinueStatus; // // Loop servicing state manipulation message until a continue message // is received. // MessageHeader.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64); MessageHeader.Buffer = (PCHAR)&ManipulateState; MessageData.MaximumLength = arrayof(KdpMessageBuffer); MessageData.Buffer = KdpMessageBuffer; KdpContextSent = FALSE; ResendPacket: // // Send event notification packet to debugger on host. Come back // here any time we see a breakin sequence. // KdSendPacket(OutPacketType, OutMessageHeader, OutMessageData, &KdpContext); // // After sending packet, if there is no response from debugger // AND the packet is for reporting symbol (un)load, the debugger // will be declared to be not present. Note If the packet is for // reporting exception, the KdSendPacket will never stop. // if (KdDebuggerNotPresent) { return ContinueSuccess; } for (;;) { // // Wait for State Manipulate Packet without timeout. // do { ReturnCode = KdReceivePacket( PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, &MessageData, &Length, &KdpContext ); KDDBG3("KdReceivePacket returned %d\n", ReturnCode); if (ReturnCode == KDP_PACKET_RESEND) { goto ResendPacket; } } while (ReturnCode == KDP_PACKET_TIMEOUT); KDDBG2("KdpSendWaitContinue: ManipulateState.ApiNumber=0x%x\n", ManipulateState.ApiNumber); // // Switch on the return message API number. // switch (ManipulateState.ApiNumber) { case DbgKdReadVirtualMemoryApi: KDDBG("KdReadVirt(%p-%p)\n", (ULONG_PTR)ManipulateState.ReadMemory.TargetBaseAddress, (ULONG_PTR)ManipulateState.ReadMemory.TargetBaseAddress + ManipulateState.ReadMemory.TransferCount); KdpReadVirtualMemory(&ManipulateState, &MessageData); break; #if 0 case DbgKdReadVirtualMemory64Api: KdpReadVirtualMemory64(&ManipulateState, &MessageData); break; #endif case DbgKdWriteVirtualMemoryApi: KDDBG("KdWritVirt(%p-%p)\n", (ULONG_PTR)ManipulateState.WriteMemory.TargetBaseAddress, (ULONG_PTR)ManipulateState.WriteMemory.TargetBaseAddress + ManipulateState.WriteMemory.TransferCount); KdpWriteVirtualMemory(&ManipulateState, &MessageData); break; #if 0 case DbgKdWriteVirtualMemory64Api: KdpWriteVirtualMemory64(&ManipulateState, &MessageData); break; #endif case DbgKdGetVersionApi: KDDBG("KdGetVersion()\n"); KdpGetVersion(&ManipulateState); break; case DbgKdGetContextApi: KDDBG("KdGetContext(p=%x)\n", ManipulateState.Processor); KdpGetContext(&ManipulateState, &MessageData, Context); break; case DbgKdReadControlSpaceApi: KDDBG("KdReadCtrl(%p-%p p=%x)\n", (ULONG_PTR)ManipulateState.ReadMemory.TargetBaseAddress, (ULONG_PTR)ManipulateState.ReadMemory.TargetBaseAddress + ManipulateState.ReadMemory.TransferCount, (ULONG_PTR)ManipulateState.Processor); KdpReadControlSpace(&ManipulateState, &MessageData, Context); break; case DbgKdWriteControlSpaceApi: KDDBG("KdWriteCtrl(%p-%p p=%x)\n", (ULONG_PTR)ManipulateState.WriteMemory.TargetBaseAddress, (ULONG_PTR)ManipulateState.WriteMemory.TargetBaseAddress + ManipulateState.WriteMemory.TransferCount, (ULONG_PTR)ManipulateState.Processor); KdpWriteControlSpace(&ManipulateState, &MessageData, Context); break; case DbgKdReadIoSpaceApi: KDDBG("KdReadIoSpace(%p size=%x p=%x)\n", (ULONG_PTR)ManipulateState.ReadWriteIo.IoAddress, (ULONG_PTR)ManipulateState.ReadWriteIo.DataSize, (ULONG_PTR)ManipulateState.Processor); KdpReadIoSpace(&ManipulateState, &MessageData, Context); break; case DbgKdWriteIoSpaceApi: KDDBG("KdWriteIoSpace(%p size=%x value=%x, p=%x)\n", (ULONG_PTR)ManipulateState.ReadWriteIo.IoAddress, (ULONG_PTR)ManipulateState.ReadWriteIo.DataSize, (ULONG_PTR)ManipulateState.ReadWriteIo.DataValue, (ULONG_PTR)ManipulateState.Processor); KdpWriteIoSpace(&ManipulateState, &MessageData, Context); break; case DbgKdSetContextApi: KDDBG("KdSetContext(p=%x)\n", ManipulateState.Processor); KdpSetContext(&ManipulateState, &MessageData, Context); break; case DbgKdWriteBreakPointApi: KDDBG("KdWriteBreak(%p)\n", ManipulateState.WriteBreakPoint.BreakPointAddress); KdpWriteBreakpoint(&ManipulateState); break; case DbgKdRestoreBreakPointApi: if (ManipulateState.RestoreBreakPoint.BreakPointHandle < 0x8 || ManipulateState.RestoreBreakPoint.BreakPointHandle > 0x1e) { KDDBG("KdRestoreBreak(%x)\n", ManipulateState.RestoreBreakPoint.BreakPointHandle); } KdpRestoreBreakpoint(&ManipulateState, &MessageData); break; case DbgKdContinueApi: KDDBG("KdContinue(%08x)\n", ManipulateState.Continue.ContinueStatus); if (NT_SUCCESS(ManipulateState.Continue.ContinueStatus)) { return ContinueSuccess; } else { return ContinueError; } break; case DbgKdContinueApi2: KDDBG("KdContinue2(%08x)\n", ManipulateState.Continue2.ContinueStatus); if (NT_SUCCESS(ManipulateState.Continue2.ContinueStatus)) { KDDBG("KdpGetStateChange()\n"); KdpGetStateChange(&ManipulateState, Context); return ContinueSuccess; } else { KDDBG("KdpContinue2 Error!\n"); return ContinueError; } break; case DbgKdReadPhysicalMemoryApi: KDDBG("KdReadPhys(%8p-%8p)\n", (ULONG_PTR)ManipulateState.ReadMemory.TargetBaseAddress, (ULONG_PTR)ManipulateState.ReadMemory.TargetBaseAddress + ManipulateState.ReadMemory.TransferCount); // KdpReadPhysicalMemory(&ManipulateState, &MessageData, Context); KdpReadPhysicalMemory(&ManipulateState, &MessageData); break; case DbgKdWritePhysicalMemoryApi: KdpWritePhysicalMemory(&ManipulateState, &MessageData); KDDBG("KdWritePhys(%8p-%8p)\n", (ULONG_PTR)ManipulateState.WriteMemory.TargetBaseAddress, (ULONG_PTR)ManipulateState.WriteMemory.TargetBaseAddress + ManipulateState.ReadMemory.TransferCount); break; case DbgKdSwitchProcessor: { // KdRestore(FALSE); bool switched = Class_Microsoft_Singularity_MpExecution::g_SwitchFrozenProcessor((int32) ManipulateState.Processor); return (switched == true) ? ContinueNextProcessor : ContinueSuccess; // KdSave(FALSE); } break; case DbgKdReadMachineSpecificRegister: KdpReadMachineSpecificRegister(&ManipulateState, &MessageData, Context); break; case DbgKdWriteMachineSpecificRegister: KdpWriteMachineSpecificRegister(&ManipulateState, &MessageData, Context); break; default: KDDBG2("Kd Bad API (0x%x)\n", ManipulateState.ApiNumber); MessageData.Length = 0; ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &MessageHeader, &MessageData, &KdpContext); break; } } } // ////////////////////////////////////////////////////////////////////////////// BOOLEAN KdPrintString( IN PSTRING Output, IN BOOLEAN Unicode ) // Routine Description: // This routine prints a string. // // Arguments: // Output - Supplies a pointer to a string descriptor for the output string. // // Return Value: // TRUE if Control-C present in input buffer after print is done. // FALSE otherwise. { UINT32 Length; STRING MessageData; STRING MessageHeader; DBGKD_DEBUG_IO DebugIo; if (KdDebuggerNotPresent) { return FALSE; } KdpLock(); // Move the output string to the message buffer. // if (Unicode) { WCHAR *pBuffer = (WCHAR *)Output->Buffer; for (int i = 0; i < Output->Length; i++) { KdpMessageBuffer[i] = (char)pBuffer[i]; } Length = Output->Length; } else { KdpCopyFromPtr(KdpMessageBuffer, Output->Buffer, Output->Length, &Length); } // If the total message length is greater than the maximum packet size, // then truncate the output string. // if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE) { Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO); } // Construct the print string message and message descriptor. // DebugIo.ApiNumber = DbgKdPrintStringApi; DebugIo.ProcessorLevel = KeProcessorLevel; DebugIo.Processor = (UINT16)KdpGetCurrentProcessorNumber(); DebugIo.PrintString.LengthOfString = Length; MessageHeader.Length = sizeof(DBGKD_DEBUG_IO); MessageHeader.Buffer = (PCHAR)&DebugIo; // Construct the print string data and data descriptor. // MessageData.Length = (UINT16)Length; MessageData.Buffer = (PCHAR) KdpMessageBuffer; // Send packet to the kernel debugger on the host machine. // KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &MessageHeader, &MessageData, &KdpContext); KdpUnlock(); return FALSE; } /////////////////////////////////////////////////////// Methods Exposed to C#. // bool Class_Microsoft_Singularity_DebugStub:: g_Trap(Struct_Microsoft_Singularity_Isal_SpillContext *context, int id) { EXCEPTION_RECORD64 er; bool handled; RtlZeroMemory(&er, sizeof(er)); if (KdDebuggerNotPresent) { return true; } KdpLock(); KDDBG("CPU %d: In g_Trap num=%d ...", KdCurrentCpuId(), id); KdDebugTrapData * trapData = KdpIsDebugTrap(context, id); if (trapData != NULL) { if (trapData->tag == KdDebugTrapData::LOADED_BINARY) { KDDBG("KD: Loaded binary %ls\n", trapData->loadedBinary.name); KdpUnlock(); LoadedBinary(trapData, context); return true; } else if (trapData->tag == KdDebugTrapData::UNLOADED_BINARY) { KDDBG("KD: Unloaded binary\n"); KdpUnlock(); UnloadedBinary(trapData, context); return true; } } KdpConvertTrapToException(&er, context, id); KdpEnter(); handled = (KdpReportExceptionStateChange(&er, context, trapData != NULL) == ContinueSuccess); KdpLeave(); KdpUnlock(); return handled; } bool Class_Microsoft_Singularity_DebugStub:: g_TrapForProcessorSwitch(Struct_Microsoft_Singularity_Isal_SpillContext *context) { EXCEPTION_RECORD64 er; KDDBG("CPU %d: TrapForProcessorSwitch:\n", KdCurrentCpuId()); RtlZeroMemory(&er, sizeof(er)); er.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER; er.ExceptionRecord = (UINT64)&er; #if ISA_IX86 || ISA_IX64 er.ExceptionAddress = context->ip; #elif ISA_ARM er.ExceptionAddress = context->pc; #endif // KdSave(FALSE); KCONTINUE_STATUS status = KdpReportExceptionStateChange(&er, context, true); // KdRestore(FALSE); return status == ContinueSuccess; } void Class_Microsoft_Singularity_DebugStub::g_AddProcessor(int cpuId) { KdpLock(); if (KeNumberProcessors <= cpuId) { KeNumberProcessors = cpuId + 1; } KdpUnlock(); } bool Class_Microsoft_Singularity_DebugStub::g_PollForBreak() { // Don't re-enter debugger if already debugging. if (KdpInDebugger) { return FALSE; } // If the debugger is enabled, see if a breakin by the kernel // debugger is pending. // We might want to enable retry here. The transports support it. if (KdDebuggerNotPresent) { return false; } // Did we already record a break from the host? if (KdpContext.KdpControlCPending) { KdpContext.KdpControlCPending = FALSE; return true; } KdpLock(); bool success = KdPollBreakIn(); KdpUnlock(); return success; } bool Class_Microsoft_Singularity_DebugStub::g_LoadedBinary(UIntPtr baseAddress, UIntPtr bytes, Class_System_String *name, uint32 checksum, uint32 timestamp, bool silent) { return g_LoadedBinary(baseAddress, bytes, (UIntPtr)&name->m_firstChar, checksum, timestamp, silent); } bool Class_Microsoft_Singularity_DebugStub::g_LoadedBinary(UIntPtr baseAddress, UIntPtr bytes, UIntPtr name, uint32 checksum, uint32 timestamp, bool silent) { if (KdDebuggerNotPresent) { return true; } KdDebugTrapData trapData; trapData.tag = KdDebugTrapData::LOADED_BINARY; trapData.loadedBinary.baseAddress = baseAddress; trapData.loadedBinary.bytes = bytes; trapData.loadedBinary.name = name; trapData.loadedBinary.checksum = checksum; trapData.loadedBinary.timestamp = timestamp; trapData.loadedBinary.silent = silent; KdNotifyTrap(&trapData); return trapData.loadedBinary.ret; } static void LoadedBinary(KdDebugTrapData *trapData, Struct_Microsoft_Singularity_Isal_SpillContext *context) { UIntPtr baseAddress = trapData->loadedBinary.baseAddress; UIntPtr bytes = trapData->loadedBinary.bytes; UIntPtr nameof = trapData->loadedBinary.name; uint32 checksum = trapData->loadedBinary.checksum; uint32 timestamp = trapData->loadedBinary.timestamp; bool silent = trapData->loadedBinary.silent; KLDR_DATA_TABLE_ENTRY_WITH_NAME *pEntry; bool good = false; WCHAR * name = trim((WCHAR *)nameof); UINT16 nlen = (UINT16)2 * wcslen(name); if (nlen > sizeof(pEntry->wzName)) { nlen = sizeof(pEntry->wzName); } KdpLock(); for (int i = 0; i < ARRAYOF(KdModuleKernelEntry); i++) { pEntry = &KdModuleKernelEntry[i]; if (pEntry->DllBase == 0) { pEntry->DllBase = (PVOID *)baseAddress; pEntry->CheckSum = checksum; pEntry->TimeDateStamp = timestamp; pEntry->LoadCount = 1; pEntry->SizeOfImage = (UINT32)bytes; memcpy(pEntry->wzName, name, nlen); RtlInitUnicodeString(&pEntry->FullDllName, name, nlen); RtlInitUnicodeString(&pEntry->BaseDllName, name, nlen); // We should insert in the right order in the list... InsertTailList(&PsLoadedModuleList, &pEntry->InLoadOrderLinks); good = true; break; } } if (!silent) { if (good) { KdpReportLoadSymbolsStateChange(pEntry->BaseDllName.Buffer, pEntry->BaseDllName.Length, (UINT64)baseAddress, (UINT32)0, checksum, (INT32)bytes, FALSE, context); } else { KdpReportLoadSymbolsStateChange(NULL, 0, (UINT64)baseAddress, (UINT32)0, checksum, (INT32)bytes, FALSE, context); } } KdpUnlock(); trapData->loadedBinary.ret = good; } bool Class_Microsoft_Singularity_DebugStub::g_UnloadedBinary(UIntPtr baseAddress, bool silent) { if (KdDebuggerNotPresent) { return true; } KdDebugTrapData trapData; trapData.tag = KdDebugTrapData::UNLOADED_BINARY; trapData.unloadedBinary.baseAddress = baseAddress; trapData.unloadedBinary.silent = silent; KdNotifyTrap(&trapData); return trapData.unloadedBinary.ret; } static void UnloadedBinary(KdDebugTrapData *trapData, Struct_Microsoft_Singularity_Isal_SpillContext *context) { UIntPtr baseAddress = trapData->unloadedBinary.baseAddress; bool silent = trapData->unloadedBinary.silent; bool good = false; KdpLock(); KLDR_DATA_TABLE_ENTRY_WITH_NAME *pEntry = NULL; for (int i = 0; i < ARRAYOF(KdModuleKernelEntry); i++) { pEntry = &KdModuleKernelEntry[i]; if (pEntry->DllBase == (PVOID*)baseAddress) { RemoveEntryList(&pEntry->InLoadOrderLinks); good = true; break; } } if (good) { if (!silent) { // Only tell debugger if we found an image name. // The debugger ignores unload requests that lack a processId (not us) // or a path name. KdpReportLoadSymbolsStateChange(pEntry->BaseDllName.Buffer, pEntry->BaseDllName.Length, (UINT64)baseAddress, (UINT32)0, 0, 0, TRUE, context); } RtlZeroMemory(pEntry, sizeof(*pEntry)); } KdpUnlock(); trapData->unloadedBinary.ret = good; } bool Class_Microsoft_Singularity_DebugStub::g_IsDebuggerPresent() { return !KdDebuggerNotPresent; } ////////////////////////////////////////////////////////////////////////////// // Note: Leaves the lock held by the client code, so it had better be trustworthy. void Class_Microsoft_Singularity_DebugStub::g_PrintBegin(WCHAR **buffer, int *length) { if (KdDebuggerNotPresent && !KdAlwaysPrintOutput) { *buffer = NULL; *length = 0; return; } else { KdpLock(); *buffer = (WCHAR *)KdpMessageBuffer; *length = sizeof(KdpMessageBuffer) / sizeof(WCHAR); } } // Note: Assumes the lock is held, so the client code had better be trustworthy. void Class_Microsoft_Singularity_DebugStub::g_PrintComplete(WCHAR *buffer, int length) { if (KdDebuggerNotPresent && !KdAlwaysPrintOutput) { return; } CHAR *out = KdpMessageBuffer; if (length > arrayof(KdpMessageBuffer)) { length = arrayof(KdpMessageBuffer); } for (int i = 0; i < length; i++) { *out++ = (CHAR)*buffer++; } // If the total message length is greater than the maximum packet size, // then truncate the output string. // if ((sizeof(DBGKD_DEBUG_IO) + length) > PACKET_MAX_SIZE) { length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO); } // // Construct the print string message and message descriptor. // DBGKD_DEBUG_IO DebugIo; DebugIo.ApiNumber = DbgKdPrintStringApi; DebugIo.ProcessorLevel = KeProcessorLevel; DebugIo.Processor = (UINT16)KdpGetCurrentProcessorNumber(); DebugIo.PrintString.LengthOfString = length; STRING MessageHeader; MessageHeader.Length = sizeof(DBGKD_DEBUG_IO); MessageHeader.Buffer = (PCHAR)&DebugIo; // // Construct the print string data and data descriptor. // STRING MessageData; MessageData.Length = (UINT16)length; MessageData.Buffer = KdpMessageBuffer; // // Send packet to the kernel debugger on the host machine. // KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &MessageHeader, &MessageData, &KdpContext); KdpUnlock(); } void Class_Microsoft_Singularity_DebugStub::g_Print(WCHAR *buf, int len) { WCHAR *buffer; int length; if (KdDebuggerNotPresent && !KdAlwaysPrintOutput) { return; } g_PrintBegin(&buffer, &length); g_PrintComplete(buf, len); } void Class_Microsoft_Singularity_DebugStub::g_Print(WCHAR *buf) { int len = 0; while (buf[len] != '\0') { len++; } g_Print(buf, len); } void Class_Microsoft_Singularity_DebugStub::g_RevertToUniprocessor() { KdpLock(); KeNumberProcessors = 1; KdpUnlock(); } void Class_Microsoft_Singularity_KernelDebugger_Kd::g_SendPacket( /*Struct_Microsoft_Singularity_KernelDebugger_KdPacketType*/ uint32 PacketType, uint8* MessageHeaderBuffer, int32 MessageHeaderLength, uint8* MessageDataBuffer, int32 MessageDataLength) { ASSERT(MessageHeaderLength >= 0); ASSERT(MessageHeaderLength < 0x10000); ASSERT(MessageDataLength >= 0); ASSERT(MessageDataLength < 0x10000); STRING MessageHeaderDesc; MessageHeaderDesc.Buffer = (PCHAR)MessageHeaderBuffer; MessageHeaderDesc.Length = (uint16)MessageHeaderLength; MessageHeaderDesc.MaximumLength = (uint16)MessageHeaderLength; STRING MessageDataDesc; MessageDataDesc.Buffer = (PCHAR)MessageDataBuffer; MessageDataDesc.Length = (uint16)MessageDataLength; MessageDataDesc.MaximumLength = (uint16)MessageDataLength; KdSendPacket( PacketType, &MessageHeaderDesc, &MessageDataDesc, &KdpContext); } /*Struct_Microsoft_Singularity_KernelDebugger_KdStatus*/ uint32 Class_Microsoft_Singularity_KernelDebugger_Kd::g_ReceivePacket( /*Struct_Microsoft_Singularity_KernelDebugger_KdPacketType*/ uint32 PacketType, uint8* MessageHeaderBuffer, int32 MessageHeaderLength, uint8* MessageDataBuffer, int32 MessageDataBufferLength, OUT int32* MessageDataLength) { UINT32 DataLength; ASSERT(MessageDataLength != NULL); *MessageDataLength = 0; STRING MessageHeaderDesc; MessageHeaderDesc.Buffer = (PCHAR)MessageHeaderBuffer; MessageHeaderDesc.Length = 0; MessageHeaderDesc.MaximumLength = (uint16)MessageHeaderLength; STRING MessageDataDesc; MessageDataDesc.Buffer = (PCHAR)MessageDataBuffer; MessageDataDesc.Length = 0; MessageDataDesc.MaximumLength = (uint16)MessageDataBufferLength; DataLength = (uint32)MessageDataBufferLength; uint32 Status = KdReceivePacket( PacketType, &MessageHeaderDesc, &MessageDataDesc, &DataLength, &KdpContext ); *MessageDataLength = (int)DataLength; return Status; } void Class_Microsoft_Singularity_KernelDebugger_Kd::g_Lock() { KdpLock(); } void Class_Microsoft_Singularity_KernelDebugger_Kd::g_Unlock() { KdpUnlock(); } // ///////////////////////////////////////////////////////////////// End of File.