singrdk/base/Kernel/Native/halkd.cpp

2703 lines
85 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// 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.