3002 lines
98 KiB
C++
3002 lines
98 KiB
C++
//
|
||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
//
|
||
// halkd.cpp: runtime support for 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
|
||
//
|
||
#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);
|
||
|
||
//
|
||
// Debugger Debugging
|
||
//
|
||
#define KDDBG if (0) kdprintf
|
||
#define KDDBG2 if (0) kdprintf
|
||
|
||
#if defined(_IA64_)
|
||
#define SIGN_EXTEND_PTR(p) p
|
||
#else
|
||
#define SIGN_EXTEND_PTR(p) ((ULONG_PTR)(LONG_PTR)(LONG)(p))
|
||
#endif
|
||
|
||
#define KeProcessorLevel 15
|
||
|
||
//
|
||
// Globals
|
||
//
|
||
extern const Struct_Microsoft_Singularity_BootInfo *g_pBootInfo;
|
||
static Struct_Microsoft_Singularity_X86_IDTP g_idt;
|
||
|
||
BOOL KdDebuggerNotPresent = 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;
|
||
static UINT16 KdpSpinBase = 0x2f00;
|
||
|
||
KDP_BREAKPOINT_TYPE KdpBreakpointInstruction = KDP_BREAKPOINT_VALUE;
|
||
BREAKPOINT_ENTRY KdpBreakpointTable[BREAKPOINT_TABLE_SIZE] = {0};
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
ULONG KdCompNumberRetries = 5;
|
||
ULONG KdCompRetryCount = 5;
|
||
ULONG KdPacketId = 0;
|
||
|
||
void (*KdSendPacket)(ULONG PacketType,
|
||
IN PSTRING MessageHeader,
|
||
IN PSTRING MessageData OPTIONAL,
|
||
IN OUT PKD_CONTEXT KdContext) = NULL;
|
||
KDP_STATUS (*KdReceivePacket)(IN ULONG PacketType,
|
||
OUT PSTRING MessageHeader,
|
||
OUT PSTRING MessageData,
|
||
OUT PULONG DataLength,
|
||
IN OUT PKD_CONTEXT KdContext) = NULL;
|
||
bool (*KdPollBreakIn)() = NULL;
|
||
|
||
//
|
||
// 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 ULONG KdModuleKernelUsed = 0;
|
||
static LIST_ENTRY PsLoadedModuleList;
|
||
static PMINIDUMP_MODULE_LIST KdMinidumpModuleList = NULL;
|
||
|
||
// KdVersionBlock =============================================================
|
||
|
||
static DBGKD_GET_VERSION64 KdVersionBlock = {
|
||
DBGKD_MAJOR_SINGULARITY << 8, // MajorVersion ... this one sort of works
|
||
0, // Minor
|
||
DBGKD_64BIT_PROTOCOL_VERSION2, // Protocol
|
||
DBGKD_VERS_FLAG_NOMM, //DBGKD_VERS_FLAG_DATA, // Flags
|
||
IMAGE_FILE_MACHINE_I386, // Machine Type
|
||
PACKET_TYPE_MAX, // Max packet
|
||
DbgKdMaximumStateChange - DbgKdMinimumStateChange, // MaxStateChange
|
||
DbgKdSetContextApi /*DbgKdMaximumManipulate*/ - DbgKdMinimumManipulate, // MaxManipulate we support
|
||
0, // Simulation
|
||
0, // Unused
|
||
0, // KernBase
|
||
(ULONG64)&PsLoadedModuleList, // PsLoadedModuleList
|
||
0 // DebuggerDataList
|
||
};
|
||
|
||
// ========================================================================
|
||
|
||
// Forward declarations
|
||
|
||
static void KdpLock(void);
|
||
static void KdpUnlock(void);
|
||
|
||
static void KdpEnter(void);
|
||
static void KdpLeave(void);
|
||
|
||
static void KdpFakeOutPsLoadedModuleList(void);
|
||
|
||
static KCONTINUE_STATUS
|
||
KdpSendWaitContinue(
|
||
IN ULONG OutPacketType,
|
||
IN PSTRING OutMessageHeader,
|
||
IN PSTRING OutMessageData OPTIONAL,
|
||
IN OUT Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
|
||
);
|
||
|
||
static void LoadedBinary(Struct_Microsoft_Singularity_X86_ThreadContext *context);
|
||
static void UnloadedBinary(Struct_Microsoft_Singularity_X86_ThreadContext *context);
|
||
|
||
extern int printf(const char *pszFmt, ...);
|
||
|
||
///////////////////////////////////////// Debugger Unique Interrupts Routines.
|
||
//
|
||
// NB: Without these, we share routines with the mainline code and we get
|
||
// caught in a loop when the debugger inserts a break after the pushfd when
|
||
// someone tries to single step through Processor:g_DisableInterrupts!
|
||
//
|
||
static __declspec(naked) bool KdpDisableInterrupts()
|
||
{
|
||
__asm {
|
||
pushfd;
|
||
pop eax;
|
||
test eax, Struct_Microsoft_Singularity_X86_EFlags_IF;
|
||
setnz al;
|
||
nop; // required so that the linker doesn't combine with g_Disable
|
||
cli;
|
||
ret;
|
||
}
|
||
}
|
||
|
||
static __declspec(naked) void KdpRestoreInterrupts(bool enabled)
|
||
{
|
||
__asm {
|
||
nop;
|
||
test cl, cl;
|
||
je done;
|
||
nop; // required so that the linker doesn't combine with g_Restore
|
||
sti;
|
||
done:
|
||
ret;
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
static volatile INT32 KdpInDebugger = 0;
|
||
static volatile bool KdpInDebuggerIntEnabled = FALSE;
|
||
|
||
#define MAXIMUM_RETRIES 20
|
||
|
||
static void KdpNulSendPacket(ULONG PacketType,
|
||
IN PSTRING MessageHeader,
|
||
IN PSTRING MessageData OPTIONAL,
|
||
IN OUT PKD_CONTEXT KdContext)
|
||
{
|
||
}
|
||
|
||
static KDP_STATUS KdpNulReceivePacket(IN ULONG PacketType,
|
||
OUT PSTRING MessageHeader,
|
||
OUT PSTRING MessageData,
|
||
OUT PULONG DataLength,
|
||
IN OUT PKD_CONTEXT KdContext)
|
||
{
|
||
return KDP_PACKET_TIMEOUT;
|
||
}
|
||
|
||
static bool KdpNulPollBreakIn()
|
||
{
|
||
return false;
|
||
}
|
||
|
||
void KdInitialize(Struct_Microsoft_Singularity_BootInfo *bi)
|
||
{
|
||
KdpLock();
|
||
|
||
if (KdpComInit(bi)) {
|
||
KdpSpinBase = 0x2f00;
|
||
KdSendPacket = KdpComSendPacket;
|
||
KdReceivePacket = KdpComReceivePacket;
|
||
KdPollBreakIn = KdpComPollBreakIn;
|
||
kdprintf("Serial Port (bi->DebugBasePort=%x).\n", bi->DebugBasePort);
|
||
}
|
||
else if (Kdp1394Init(bi)) {
|
||
KdpSpinBase = 0x4f00;
|
||
KdSendPacket = Kdp1394SendPacket;
|
||
KdReceivePacket = Kdp1394ReceivePacket;
|
||
KdPollBreakIn = Kdp1394PollBreakIn;
|
||
kdprintf("1394 Port (bi->DebugBasePort=%x).\n", bi->DebugBasePort);
|
||
}
|
||
else {
|
||
kdprintf("No debugger.\n");
|
||
KdSendPacket = KdpNulSendPacket;
|
||
KdReceivePacket = KdpNulReceivePacket;
|
||
KdPollBreakIn = KdpNulPollBreakIn;
|
||
KdDebuggerNotPresent = true;
|
||
}
|
||
|
||
// Retries are set to this after boot
|
||
KdpContext.KdpDefaultRetries = MAXIMUM_RETRIES;
|
||
|
||
KdpUnlock();
|
||
|
||
KdpFakeOutPsLoadedModuleList();
|
||
}
|
||
|
||
static void KdpLock()
|
||
{
|
||
for (;;) {
|
||
bool enabled = KdpDisableInterrupts();
|
||
if (InterlockedCompareExchange(&KdpInDebugger, 1, 0) == 0) {
|
||
KdpInDebuggerIntEnabled = enabled;
|
||
return;
|
||
}
|
||
KdpRestoreInterrupts(enabled);
|
||
__asm pause
|
||
}
|
||
}
|
||
|
||
static void KdpUnlock()
|
||
{
|
||
KdpInDebugger = 0;
|
||
KdpRestoreInterrupts(KdpInDebuggerIntEnabled);
|
||
}
|
||
|
||
static void KdpEnter()
|
||
{
|
||
if (KeNumberProcessors > 1) {
|
||
Class_Microsoft_Singularity_MpExecution::g_FreezeAllProcessors();
|
||
}
|
||
}
|
||
|
||
static void KdpLeave()
|
||
{
|
||
if (KeNumberProcessors > 1) {
|
||
Class_Microsoft_Singularity_MpExecution::g_ThawAllProcessors();
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
extern int strformat(void (*pfOutput)(void *pContext, char c), void *pContext,
|
||
const char * pszFmt, va_list args);
|
||
|
||
#define KD_LEFT 0
|
||
#define KD_HEIGHT 46
|
||
|
||
static UINT16 kdcurs = KD_LEFT;
|
||
static UINT16 kdattr = 0x2f00;
|
||
|
||
static void koutput(void *pContext, char c)
|
||
{
|
||
//
|
||
// 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;
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
void KdpSpin()
|
||
{
|
||
static UINT8 state = 0;
|
||
|
||
*((UINT16 *)0xb809e) = KdpSpinBase + ("+-|*" [state++ & 0x3]);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
ULONG KdpComputeChecksum(IN PCHAR Buffer, IN ULONG Length)
|
||
{
|
||
// Compute the checksum for the string passed in.
|
||
ULONG Checksum = 0;
|
||
|
||
while (Length > 0) {
|
||
Checksum = Checksum + (ULONG)*(PUCHAR)Buffer++;
|
||
Length--;
|
||
}
|
||
|
||
return(Checksum);
|
||
} // KdpComputeChecksum
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
static
|
||
VOID KdSingularityToWindbgContext(IN CONST Struct_Microsoft_Singularity_X86_ThreadContext *singularity,
|
||
OUT CONTEXT *windbg)
|
||
{
|
||
RtlZeroMemory(windbg, sizeof(*windbg));
|
||
|
||
windbg->ContextFlags = (CONTEXT_CONTROL |
|
||
CONTEXT_INTEGER |
|
||
CONTEXT_SEGMENTS |
|
||
CONTEXT_DEBUG_REGISTERS);
|
||
|
||
// CONTEXT_FULL;
|
||
windbg->Eax = singularity->eax;
|
||
windbg->Ebx = singularity->ebx;
|
||
windbg->Ecx = singularity->ecx;
|
||
windbg->Edx = singularity->edx;
|
||
windbg->Esp = singularity->esp;
|
||
windbg->Ebp = singularity->ebp;
|
||
windbg->Esi = singularity->esi;
|
||
windbg->Edi = singularity->edi;
|
||
windbg->Eip = singularity->eip;
|
||
windbg->EFlags = singularity->efl;
|
||
|
||
// CONTEXT_FLOATING_POINT
|
||
if (singularity->regs) {
|
||
windbg->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||
|
||
#if 0
|
||
PUCHAR pmmx = (PUCHAR)&singularity->mmx;
|
||
kdprintf(" MMX=%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
|
||
pmmx[0], pmmx[1], pmmx[2], pmmx[3],
|
||
pmmx[4], pmmx[5], pmmx[6], pmmx[7],
|
||
pmmx[8], pmmx[9], pmmx[10], pmmx[11],
|
||
pmmx[12], pmmx[13], pmmx[14], pmmx[15]);
|
||
kdprintf(" MMX=%04x %04x %02x %03x %04x:%08x %04x:%08x\n",
|
||
singularity->mmx.fcw,
|
||
singularity->mmx.fsw,
|
||
singularity->mmx.ftw,
|
||
singularity->mmx.fop,
|
||
singularity->mmx.cs,
|
||
singularity->mmx.eip,
|
||
singularity->mmx.ds,
|
||
singularity->mmx.dp);
|
||
#endif
|
||
|
||
windbg->FloatSave.ControlWord = singularity->mmx.fcw;
|
||
windbg->FloatSave.StatusWord = singularity->mmx.fsw;
|
||
windbg->FloatSave.TagWord = singularity->mmx.ftw;
|
||
windbg->FloatSave.ErrorOffset = singularity->mmx.eip;
|
||
windbg->FloatSave.ErrorSelector = singularity->mmx.cs;
|
||
windbg->FloatSave.DataOffset = singularity->mmx.dp;
|
||
windbg->FloatSave.DataSelector = singularity->mmx.ds;
|
||
|
||
memcpy((uint8*)windbg->FloatSave.RegisterArea+0, &singularity->mmx.st0, 10);
|
||
memcpy((uint8*)windbg->FloatSave.RegisterArea+10, &singularity->mmx.st1, 10);
|
||
memcpy((uint8*)windbg->FloatSave.RegisterArea+20, &singularity->mmx.st2, 10);
|
||
memcpy((uint8*)windbg->FloatSave.RegisterArea+30, &singularity->mmx.st3, 10);
|
||
memcpy((uint8*)windbg->FloatSave.RegisterArea+40, &singularity->mmx.st4, 10);
|
||
memcpy((uint8*)windbg->FloatSave.RegisterArea+50, &singularity->mmx.st5, 10);
|
||
memcpy((uint8*)windbg->FloatSave.RegisterArea+60, &singularity->mmx.st6, 10);
|
||
memcpy((uint8*)windbg->FloatSave.RegisterArea+70, &singularity->mmx.st7, 10);
|
||
}
|
||
|
||
// CONTEXT_EXTENDED_REGISTERS
|
||
if (singularity->regs & 1) {
|
||
windbg->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
|
||
memcpy(windbg->ExtendedRegisters, &singularity->mmx, 512);
|
||
}
|
||
|
||
//
|
||
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
|
||
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
|
||
// included in CONTEXT_FULL.
|
||
//
|
||
windbg->Dr0 = singularity->dr0;
|
||
windbg->Dr1 = singularity->dr1;
|
||
windbg->Dr2 = singularity->dr2;
|
||
windbg->Dr3 = singularity->dr3;
|
||
windbg->Dr6 = singularity->dr6;
|
||
windbg->Dr7 = singularity->dr7;
|
||
|
||
#if 0
|
||
__asm {
|
||
mov ebx, windbg;
|
||
|
||
mov eax, dr0;
|
||
mov [ebx]CONTEXT.Dr0, eax;
|
||
mov eax, dr1;
|
||
mov [ebx]CONTEXT.Dr1, eax;
|
||
mov eax, dr2;
|
||
mov [ebx]CONTEXT.Dr2, eax;
|
||
mov eax, dr3;
|
||
mov [ebx]CONTEXT.Dr3, eax;
|
||
mov eax, dr6;
|
||
mov [ebx]CONTEXT.Dr6, eax;
|
||
mov eax, dr7;
|
||
mov [ebx]CONTEXT.Dr7, eax;
|
||
}
|
||
#endif
|
||
|
||
#if 1
|
||
//
|
||
// This section is specified/returned if the
|
||
// ContextFlags word contains the flag CONTEXT_SEGMENTS.
|
||
//
|
||
__asm {
|
||
mov ebx, windbg;
|
||
|
||
xor eax, eax;
|
||
mov ax, gs;
|
||
mov [ebx]CONTEXT.SegGs, eax;
|
||
mov ax, fs;
|
||
mov [ebx]CONTEXT.SegFs, eax;
|
||
mov ax, es;
|
||
mov [ebx]CONTEXT.SegEs, eax;
|
||
mov ax, ds;
|
||
mov [ebx]CONTEXT.SegDs, eax;
|
||
}
|
||
|
||
//
|
||
// This section is specified/returned if the
|
||
// ContextFlags word contains the flag CONTEXT_CONTROL.
|
||
//
|
||
|
||
__asm {
|
||
mov ebx, windbg;
|
||
|
||
xor eax, eax;
|
||
mov ax, ss;
|
||
mov [ebx]CONTEXT.SegSs, eax;
|
||
}
|
||
|
||
windbg->SegCs = singularity->cs0;
|
||
#endif
|
||
}
|
||
|
||
VOID KdWindbgToSingularityContext(IN CONST CONTEXT *windbg,
|
||
OUT Struct_Microsoft_Singularity_X86_ThreadContext *singularity)
|
||
{
|
||
singularity->eax = windbg->Eax;
|
||
singularity->ebx = windbg->Ebx;
|
||
singularity->ecx = windbg->Ecx;
|
||
singularity->edx = windbg->Edx;
|
||
singularity->esp = windbg->Esp;
|
||
singularity->ebp = windbg->Ebp;
|
||
singularity->esi = windbg->Esi;
|
||
singularity->edi = windbg->Edi;
|
||
singularity->eip = windbg->Eip;
|
||
singularity->efl = windbg->EFlags;
|
||
|
||
// CONTEXT_FLOATING_POINT
|
||
if (windbg->ContextFlags & CONTEXT_FLOATING_POINT) {
|
||
singularity->mmx.fcw = (uint16)windbg->FloatSave.ControlWord;
|
||
singularity->mmx.fsw = (uint16)windbg->FloatSave.StatusWord;
|
||
singularity->mmx.ftw = (uint16)windbg->FloatSave.TagWord;
|
||
singularity->mmx.cs = (uint16)windbg->FloatSave.ErrorSelector;
|
||
singularity->mmx.eip = windbg->FloatSave.ErrorOffset;
|
||
singularity->mmx.ds = (uint16)windbg->FloatSave.DataSelector;
|
||
singularity->mmx.dp = windbg->FloatSave.DataOffset;
|
||
memcpy(&singularity->mmx.st0, windbg->FloatSave.RegisterArea+0, 10);
|
||
memcpy(&singularity->mmx.st1, windbg->FloatSave.RegisterArea+10, 10);
|
||
memcpy(&singularity->mmx.st2, windbg->FloatSave.RegisterArea+20, 10);
|
||
memcpy(&singularity->mmx.st3, windbg->FloatSave.RegisterArea+30, 10);
|
||
memcpy(&singularity->mmx.st4, windbg->FloatSave.RegisterArea+40, 10);
|
||
memcpy(&singularity->mmx.st5, windbg->FloatSave.RegisterArea+50, 10);
|
||
memcpy(&singularity->mmx.st6, windbg->FloatSave.RegisterArea+60, 10);
|
||
memcpy(&singularity->mmx.st7, windbg->FloatSave.RegisterArea+70, 10);
|
||
}
|
||
|
||
// CONTEXT_EXTENDED_REGISTERS
|
||
if (windbg->ContextFlags & CONTEXT_EXTENDED_REGISTERS) {
|
||
memcpy(&singularity->mmx, windbg->ExtendedRegisters, 512);
|
||
}
|
||
|
||
//
|
||
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
|
||
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
|
||
// included in CONTEXT_FULL.
|
||
//
|
||
if (windbg->ContextFlags & CONTEXT_DEBUG_REGISTERS) {
|
||
singularity->dr0 = windbg->Dr0;
|
||
singularity->dr1 = windbg->Dr1;
|
||
singularity->dr2 = windbg->Dr2;
|
||
singularity->dr3 = windbg->Dr3;
|
||
singularity->dr6 = windbg->Dr6;
|
||
singularity->dr7 = windbg->Dr7;
|
||
#if 0
|
||
__asm {
|
||
mov ebx, windbg;
|
||
mov eax, [ebx]CONTEXT.Dr0;
|
||
mov dr0, eax;
|
||
mov eax, [ebx]CONTEXT.Dr1;
|
||
mov dr1, eax;
|
||
mov eax, [ebx]CONTEXT.Dr2;
|
||
mov dr2, eax;
|
||
mov eax, [ebx]CONTEXT.Dr3;
|
||
mov dr3, eax;
|
||
mov eax, 0; //CONTEXT.Dr6 : DR6 is reset when changing BPTs.
|
||
mov dr6, eax;
|
||
mov eax, [ebx]CONTEXT.Dr7;
|
||
mov eax, dr7;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
//
|
||
// Misc KD functions
|
||
//
|
||
|
||
|
||
NTSTATUS
|
||
KdpCopyMemoryChunks(
|
||
ULONG64 Address,
|
||
PVOID Buffer,
|
||
ULONG TotalSize,
|
||
ULONG ChunkSize,
|
||
ULONG Flags,
|
||
PULONG 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.
|
||
//
|
||
// Return Value:
|
||
// NTSTATUS
|
||
{
|
||
ULONG Length;
|
||
ULONG CopyChunk;
|
||
// NTSTATUS Status;
|
||
#if defined(_IA64_)
|
||
ULONG64 AddressStart = Address;
|
||
#endif
|
||
|
||
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;
|
||
}
|
||
|
||
Address &= 0xffffffff;
|
||
if (Address < Struct_Microsoft_Singularity_BootInfo_PHYSICAL_DISABLED) {
|
||
break;
|
||
}
|
||
if (Address == 0) {
|
||
break;
|
||
}
|
||
#if PAGING
|
||
ULONG64 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 = ULONG64(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
|
||
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) {
|
||
#if defined(_IA64_)
|
||
//
|
||
// KeSweepCurrentIcacheRange requires a valid virtual address.
|
||
// It is used because KeSweepCurrentICache does not work until
|
||
// the HAL as been initialized.
|
||
//
|
||
|
||
if (Flags & MMDBG_COPY_PHYSICAL) {
|
||
KeSweepCurrentIcache();
|
||
}
|
||
else {
|
||
KeSweepCurrentIcacheRange((PVOID)AddressStart, TotalSize - Length);
|
||
}
|
||
#else
|
||
__asm wbinvd;
|
||
// KeSweepCurrentIcache();
|
||
#endif
|
||
|
||
}
|
||
|
||
return Length != 0 ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
|
||
}
|
||
|
||
static
|
||
VOID
|
||
KdpSetCommonState(
|
||
IN ULONG NewState,
|
||
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context,
|
||
OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange
|
||
)
|
||
{
|
||
PCHAR PcMemory = (PCHAR)x86Context->eip;
|
||
ULONG InstrCount;
|
||
PUCHAR InstrStream;
|
||
|
||
WaitStateChange->NewState = NewState;
|
||
WaitStateChange->ProcessorLevel = KeProcessorLevel;
|
||
WaitStateChange->Processor = GetCurrentProcessorNumber();
|
||
WaitStateChange->NumberProcessors = KeNumberProcessors;
|
||
WaitStateChange->Thread = SIGN_EXTEND_PTR(x86Context->_thread);
|
||
WaitStateChange->ProgramCounter = SIGN_EXTEND_PTR(x86Context->eip);
|
||
|
||
RtlZeroMemory(&WaitStateChange->AnyControlReport,
|
||
sizeof(WaitStateChange->AnyControlReport));
|
||
|
||
//
|
||
// Copy instruction stream immediately following location of event.
|
||
//
|
||
|
||
InstrStream = WaitStateChange->ControlReport.InstructionStream;
|
||
KdpCopyFromPtr(InstrStream, PcMemory, DBGKD_MAXSTREAM, &InstrCount);
|
||
WaitStateChange->ControlReport.InstructionCount = (USHORT)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);
|
||
// }
|
||
}
|
||
|
||
VOID
|
||
KdpSetContextState(
|
||
IN OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange,
|
||
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
|
||
)
|
||
// Routine Description:
|
||
// Fill in the Wait_State_Change message record.
|
||
//
|
||
// Arguments:
|
||
// WaitStateChange - Supplies pointer to record to fill in
|
||
// x86Context - Supplies a pointer to a context record.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
#if 0
|
||
PKPRCB Prcb;
|
||
|
||
//
|
||
// Special registers for the x86
|
||
//
|
||
Prcb = KeGetCurrentPrcb();
|
||
WaitStateChange->ControlReport.Dr6 = Prcb->ProcessorState.SpecialRegisters.KernelDr6;
|
||
WaitStateChange->ControlReport.Dr7 = Prcb->ProcessorState.SpecialRegisters.KernelDr7;
|
||
#endif
|
||
|
||
UINT32 _dr6;
|
||
UINT32 _dr7;
|
||
UINT16 _cs;
|
||
UINT16 _ds;
|
||
UINT16 _es;
|
||
UINT16 _fs;
|
||
|
||
__asm {
|
||
mov eax, dr6;
|
||
mov _dr6, eax;
|
||
mov eax, dr7;
|
||
mov _dr7, eax;
|
||
mov ax, cs;
|
||
mov _cs, ax;
|
||
mov ax, ds;
|
||
mov _ds, ax;
|
||
mov ax, es;
|
||
mov _es, ax;
|
||
mov ax, fs;
|
||
mov _fs, ax;
|
||
}
|
||
|
||
// I'm not sure we're handling dr6 right here.
|
||
KDDBG("KdpSetContextState dr6=%08x dr7=%08x cs=%04x/%04x\n",
|
||
_dr6, _dr7, _cs, _ds);
|
||
|
||
WaitStateChange->ControlReport.Dr6 = _dr6;
|
||
WaitStateChange->ControlReport.Dr7 = _dr7;
|
||
WaitStateChange->ControlReport.SegCs = _cs;
|
||
WaitStateChange->ControlReport.SegDs = _ds;
|
||
WaitStateChange->ControlReport.SegEs = _es;
|
||
WaitStateChange->ControlReport.SegFs = _fs;
|
||
WaitStateChange->ControlReport.EFlags = x86Context->efl;
|
||
WaitStateChange->ControlReport.ReportFlags = X86_REPORT_INCLUDES_SEGS;
|
||
|
||
#if !PAGING
|
||
// Let the debugger know so that it doesn't have to retrieve the CS descriptor.
|
||
WaitStateChange->ControlReport.ReportFlags |= X86_REPORT_STANDARD_CS;
|
||
#endif
|
||
}
|
||
|
||
ULONG
|
||
WcsToStr(WCHAR *pwcsSrc, ULONG Length, PCHAR pszDst)
|
||
{
|
||
for (ULONG n = 0; n < Length; n++) {
|
||
*pszDst++ = (char)*pwcsSrc++;
|
||
}
|
||
*pszDst++ = '\0';
|
||
|
||
return Length + 1;
|
||
}
|
||
|
||
bool
|
||
KdpReportLoadSymbolsStateChange(
|
||
IN WCHAR *PathName,
|
||
IN ULONG PathNameLength,
|
||
IN ULONG64 BaseOfDll,
|
||
IN ULONG ProcessId,
|
||
IN ULONG CheckSum,
|
||
IN ULONG SizeOfImage,
|
||
IN BOOLEAN UnloadSymbols,
|
||
IN OUT Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
|
||
)
|
||
// 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.
|
||
//
|
||
// Return Value:
|
||
// A value of TRUE is returned if the exception is handled. Otherwise, a
|
||
// value of FALSE is returned.
|
||
{
|
||
// 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", x86Context);
|
||
|
||
do {
|
||
//
|
||
// Construct the wait state change message and message descriptor.
|
||
//
|
||
|
||
KdpSetCommonState(DbgKdLoadSymbolsStateChange, x86Context,
|
||
&WaitStateChange);
|
||
|
||
WaitStateChange.u.LoadSymbols.UnloadSymbols = UnloadSymbols;
|
||
WaitStateChange.u.LoadSymbols.BaseOfDll = BaseOfDll;
|
||
WaitStateChange.u.LoadSymbols.ProcessId = ProcessId;
|
||
WaitStateChange.u.LoadSymbols.CheckSum = CheckSum;
|
||
WaitStateChange.u.LoadSymbols.SizeOfImage = SizeOfImage;
|
||
if (PathName != NULL) {
|
||
WaitStateChange.u.LoadSymbols.PathNameLength =
|
||
WcsToStr(PathName, PathNameLength, KdpMessageBuffer);
|
||
}
|
||
else {
|
||
WaitStateChange.u.LoadSymbols.PathNameLength = 0;
|
||
}
|
||
MessageData.Buffer = KdpMessageBuffer;
|
||
MessageData.Length = (USHORT)WaitStateChange.u.LoadSymbols.PathNameLength;
|
||
|
||
KdpSetContextState(&WaitStateChange, x86Context);
|
||
|
||
MessageHeader.Length = sizeof(WaitStateChange);
|
||
MessageHeader.Buffer = (PCHAR)&WaitStateChange;
|
||
|
||
Status = KdpSendWaitContinue(
|
||
PACKET_TYPE_KD_STATE_CHANGE64,
|
||
&MessageHeader,
|
||
&MessageData,
|
||
x86Context
|
||
);
|
||
|
||
} while (Status == ContinueProcessorReselected) ;
|
||
|
||
return (Status == ContinueSuccess) ? true : false;
|
||
}
|
||
|
||
static
|
||
KCONTINUE_STATUS
|
||
KdpReportExceptionStateChange(
|
||
IN PEXCEPTION_RECORD64 ExceptionRecord,
|
||
IN OUT Struct_Microsoft_Singularity_X86_ThreadContext *x86Context,
|
||
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.
|
||
// x86Context - 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", x86Context);
|
||
|
||
do {
|
||
|
||
//
|
||
// Construct the wait state change message and message descriptor.
|
||
//
|
||
|
||
KdpSetCommonState(DbgKdExceptionStateChange, x86Context,
|
||
&WaitStateChange);
|
||
|
||
WaitStateChange.u.Exception.ExceptionRecord = *ExceptionRecord;
|
||
WaitStateChange.u.Exception.FirstChance = FirstChance;
|
||
|
||
KdpSetContextState(&WaitStateChange, x86Context);
|
||
|
||
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,
|
||
x86Context
|
||
);
|
||
} 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.
|
||
// x86Context - Supplies a pointer to the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
ULONG Length;
|
||
STRING MessageHeader;
|
||
|
||
//
|
||
// Trim the transfer count to fit in a single message.
|
||
//
|
||
|
||
Length = m->u.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.
|
||
//
|
||
if (m->u.ReadMemory.TargetBaseAddress >= 0x80000000) {
|
||
KDDBG(" Read out of range!\n");
|
||
|
||
for (UINT i = 0; i < Length; i++) {
|
||
AdditionalData->Buffer[i] = 0;
|
||
}
|
||
Length = 0;
|
||
}
|
||
else {
|
||
m->ReturnStatus =
|
||
KdpCopyMemoryChunks(m->u.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 = (USHORT)Length;
|
||
m->u.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.
|
||
// x86Context - Supplies a pointer to the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
|
||
STRING MessageHeader;
|
||
|
||
//
|
||
// Move the data to the destination buffer.
|
||
//
|
||
|
||
m->ReturnStatus =
|
||
KdpCopyMemoryChunks(m->u.WriteMemory.TargetBaseAddress,
|
||
AdditionalData->Buffer,
|
||
AdditionalData->Length,
|
||
0,
|
||
MMDBG_COPY_WRITE | MMDBG_COPY_UNSAFE,
|
||
&m->u.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.
|
||
// x86Context - Supplies a pointer to the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
ULONG Length;
|
||
STRING MessageHeader;
|
||
|
||
//
|
||
// Trim the transfer count to fit in a single message.
|
||
//
|
||
|
||
Length = m->u.ReadMemory.TransferCount;
|
||
if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) {
|
||
Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
|
||
}
|
||
|
||
m->ReturnStatus =
|
||
KdpCopyMemoryChunks(m->u.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 = (USHORT)Length;
|
||
m->u.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.
|
||
// x86Context - Supplies a pointer to the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
|
||
STRING MessageHeader;
|
||
|
||
//
|
||
// Move the data to the destination buffer.
|
||
//
|
||
|
||
m->ReturnStatus =
|
||
KdpCopyMemoryChunks(m->u.WriteMemory.TargetBaseAddress,
|
||
AdditionalData->Buffer,
|
||
AdditionalData->Length,
|
||
0,
|
||
MMDBG_COPY_WRITE | MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL,
|
||
&m->u.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_X86_ThreadContext *x86Context
|
||
)
|
||
// 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.
|
||
// x86Context - Supplies a pointer to the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
|
||
STRING MessageHeader;
|
||
|
||
//
|
||
// Read the MSR
|
||
//
|
||
|
||
UINT32 msr = m->u.ReadWriteMsr.Msr;
|
||
UINT32 hi, lo;
|
||
|
||
__asm {
|
||
mov ecx, msr;
|
||
rdmsr;
|
||
mov hi, edx;
|
||
mov lo, eax;
|
||
}
|
||
|
||
m->u.ReadWriteMsr.DataValueHigh = hi;
|
||
m->u.ReadWriteMsr.DataValueLow = lo;
|
||
m->ReturnStatus = STATUS_SUCCESS;
|
||
|
||
//
|
||
// 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
|
||
KdpWriteMachineSpecificRegister(
|
||
IN PDBGKD_MANIPULATE_STATE64 m,
|
||
IN PSTRING AdditionalData,
|
||
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
|
||
)
|
||
// 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.
|
||
// x86Context - Supplies a pointer to the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
|
||
STRING MessageHeader;
|
||
|
||
//
|
||
// Write the MSR
|
||
//
|
||
|
||
UINT32 msr = m->u.ReadWriteMsr.Msr;
|
||
UINT32 hi = m->u.ReadWriteMsr.DataValueHigh, lo = m->u.ReadWriteMsr.DataValueLow;
|
||
|
||
__asm {
|
||
mov ecx, msr;
|
||
mov edx, hi;
|
||
mov eax, lo;
|
||
wrmsr;
|
||
}
|
||
|
||
m->ReturnStatus = STATUS_SUCCESS;
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
static void KdpFakeOutPsLoadedModuleList()
|
||
{
|
||
UINT8* pbImage = (UINT8*)g_pBootInfo->DumpAddr32;
|
||
PMINIDUMP_HEADER pHeader = (PMINIDUMP_HEADER)(pbImage + 0);
|
||
|
||
#define VERBOSE 1
|
||
#if VERBOSE
|
||
printf("KdpFakeOutPsLoadedModuleList (%p):\n"
|
||
" BootInfo at %p MINIDUMP_HEADER at %p\n",
|
||
&PsLoadedModuleList, g_pBootInfo, pHeader);
|
||
#endif
|
||
|
||
// Need to build a data structure which looks like NT's PsLoadedModuleList
|
||
InitializeListHead(&PsLoadedModuleList);
|
||
|
||
PMINIDUMP_DIRECTORY pDir
|
||
= (PMINIDUMP_DIRECTORY)(pbImage + pHeader->StreamDirectoryRva);
|
||
|
||
for (UINT i = 0; i < pHeader->NumberOfStreams; i++) {
|
||
if (pDir[i].StreamType == ModuleListStream) {
|
||
KdMinidumpModuleList = (PMINIDUMP_MODULE_LIST)(pbImage + pDir[i].Location.Rva);
|
||
break;
|
||
}
|
||
}
|
||
if (KdMinidumpModuleList == NULL) {
|
||
#if VERBOSE
|
||
printf("Couldn't find module list.\n");
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
KdVersionBlock.KernBase = (ULONG64)KdMinidumpModuleList->Modules[0].BaseOfImage;
|
||
|
||
#if VERBOSE
|
||
printf("MODULE_LIST: %d entries\n", KdMinidumpModuleList->NumberOfModules);
|
||
#endif
|
||
|
||
#if 1
|
||
// We manual include these modules to allow debugging very early in the boot cycle.
|
||
for (UINT m = 0; m < KdMinidumpModuleList->NumberOfModules &&
|
||
m < (sizeof(KdModuleKernelEntry)/sizeof(KdModuleKernelEntry[0])); m++) {
|
||
|
||
PMINIDUMP_MODULE pModule = &KdMinidumpModuleList->Modules[m];
|
||
KLDR_DATA_TABLE_ENTRY_WITH_NAME *pEntry = &KdModuleKernelEntry[KdModuleKernelUsed++];
|
||
|
||
WCHAR *name = trim((WCHAR *)((pbImage + pModule->ModuleNameRva)+4));
|
||
USHORT nlen = (USHORT)2 * wcslen(name);
|
||
if (nlen > sizeof(pEntry->wzName)) {
|
||
nlen = sizeof(pEntry->wzName);
|
||
}
|
||
|
||
pEntry->DllBase = (PVOID *)pModule->BaseOfImage;
|
||
pEntry->CheckSum = pModule->CheckSum;
|
||
pEntry->TimeDateStamp = pModule->TimeDateStamp;
|
||
pEntry->LoadCount = 1;
|
||
pEntry->SizeOfImage = pModule->SizeOfImage;
|
||
memcpy(pEntry->wzName, name, nlen);
|
||
RtlInitUnicodeString(&pEntry->BaseDllName, pEntry->wzName, nlen);
|
||
RtlInitUnicodeString(&pEntry->FullDllName, pEntry->wzName, nlen); // Write back on self.
|
||
|
||
#if VERBOSE
|
||
printf("%4d: BaseOfImage %8lx SizeOfImage %8x ModuleNameRva %8x\n",
|
||
m,
|
||
pModule->BaseOfImage,
|
||
pModule->SizeOfImage,
|
||
pModule->ModuleNameRva);
|
||
printf(" ModuleName: %ls (%p)\n",
|
||
pEntry->BaseDllName.Buffer,
|
||
pEntry);
|
||
#endif
|
||
|
||
InsertTailList(&PsLoadedModuleList, &pEntry->InLoadOrderLinks);
|
||
}
|
||
#endif
|
||
}
|
||
|
||
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
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
*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.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
STRING messageHeader;
|
||
|
||
messageHeader.Length = sizeof(*m);
|
||
messageHeader.Buffer = (PCHAR)m;
|
||
|
||
KdpSysGetVersion(&m->u.GetVersion64);
|
||
|
||
//
|
||
// the usual stuff
|
||
//
|
||
m->ReturnStatus = STATUS_SUCCESS;
|
||
m->ApiNumber = DbgKdGetVersionApi;
|
||
|
||
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
&messageHeader,
|
||
NULL,
|
||
&KdpContext
|
||
);
|
||
|
||
return;
|
||
} // KdGetVersion
|
||
|
||
static inline ULONG min(ULONG a, ULONG b)
|
||
{
|
||
return a < b ? a : b;
|
||
}
|
||
|
||
static
|
||
VOID
|
||
KdpReadControlSpace(
|
||
IN PDBGKD_MANIPULATE_STATE64 m,
|
||
IN PSTRING AdditionalData,
|
||
IN Struct_Microsoft_Singularity_X86_ThreadContext * x86Context
|
||
)
|
||
// 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.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
PDBGKD_READ_MEMORY64 a = &m->u.ReadMemory;
|
||
STRING MessageHeader;
|
||
ULONG Length;
|
||
|
||
MessageHeader.Length = sizeof(*m);
|
||
MessageHeader.Buffer = (PCHAR)m;
|
||
|
||
ASSERT(AdditionalData->Length == 0);
|
||
|
||
Length = min(min(a->TransferCount,
|
||
PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)),
|
||
sizeof(KPROCESSOR_STATE) - (ULONG)a->TargetBaseAddress);
|
||
|
||
if ((a->TargetBaseAddress + Length <= sizeof(KPROCESSOR_STATE)) &&
|
||
(m->Processor < (ULONG)KeNumberProcessors)) {
|
||
PKPROCESSOR_STATE ProcessorState = &KdpProcessorState[m->Processor];
|
||
if (a->TargetBaseAddress < sizeof(CONTEXT)) {
|
||
// Need to update the thread context information.
|
||
KdSingularityToWindbgContext(x86Context, &ProcessorState->ContextFrame);
|
||
}
|
||
if (a->TargetBaseAddress + Length > sizeof(CONTEXT)) {
|
||
// Need to update the processor context information.
|
||
// ASSERT(m->Processor == 0); // MP support broken.
|
||
|
||
ProcessorState->SpecialRegisters.Cr2 = x86Context->cr2;
|
||
ProcessorState->SpecialRegisters.Cr3 = (ULONG)x86Context->cr3;
|
||
KSPECIAL_REGISTERS *pksp = &ProcessorState->SpecialRegisters;
|
||
|
||
__asm {
|
||
mov ebx, pksp;
|
||
|
||
mov eax, cr0;
|
||
mov [ebx].Cr0, eax;
|
||
mov eax, cr3;
|
||
mov [ebx].Cr3, eax;
|
||
_emit 0x0f; // mov eax,cr4
|
||
_emit 0x20;
|
||
_emit 0xe0;
|
||
mov [ebx].Cr4, eax;
|
||
|
||
// XXX save TR should save segment regs as well.
|
||
str ax;
|
||
mov [ebx].Tr, ax;
|
||
#if 0
|
||
mov eax, dr0;
|
||
mov [ebx].KernelDr0, eax;
|
||
mov eax, dr1;
|
||
mov [ebx].KernelDr1, eax;
|
||
mov eax, dr2;
|
||
mov [ebx].KernelDr2, eax;
|
||
mov eax, dr3;
|
||
mov [ebx].KernelDr3, eax;
|
||
mov eax, dr6;
|
||
mov [ebx].KernelDr6, eax;
|
||
mov eax, dr7;
|
||
mov [ebx].KernelDr7, eax;
|
||
#endif
|
||
}
|
||
|
||
const Struct_Microsoft_Singularity_CpuInfo* cpuInfo = &g_pBootInfo->Cpu0 + m->Processor;
|
||
ProcessorState->SpecialRegisters.Gdtr.Pad = cpuInfo->GdtPtr.pad;
|
||
ProcessorState->SpecialRegisters.Gdtr.Limit = cpuInfo->GdtPtr.limit;
|
||
ProcessorState->SpecialRegisters.Gdtr.Base = cpuInfo->GdtPtr.addr;
|
||
|
||
ProcessorState->SpecialRegisters.Idtr.Pad = g_idt.pad;
|
||
ProcessorState->SpecialRegisters.Idtr.Limit = g_idt.limit;
|
||
ProcessorState->SpecialRegisters.Idtr.Base = g_idt.addr;
|
||
}
|
||
|
||
m->ReturnStatus = KdpCopyToPtr(AdditionalData->Buffer,
|
||
((uint8*)ProcessorState) + a->TargetBaseAddress,
|
||
Length,
|
||
&Length);
|
||
}
|
||
else {
|
||
m->ReturnStatus = STATUS_UNSUCCESSFUL;
|
||
Length = 0;
|
||
}
|
||
|
||
AdditionalData->Length = (USHORT)Length;
|
||
a->ActualBytesRead = Length;
|
||
|
||
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
&MessageHeader,
|
||
AdditionalData,
|
||
&KdpContext);
|
||
}
|
||
|
||
static
|
||
VOID
|
||
KdpWriteControlSpace(
|
||
IN PDBGKD_MANIPULATE_STATE64 m,
|
||
IN PSTRING AdditionalData,
|
||
IN Struct_Microsoft_Singularity_X86_ThreadContext * x86Context
|
||
)
|
||
// 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.
|
||
// x86Context - Supplies the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
PDBGKD_WRITE_MEMORY64 a = &m->u.WriteMemory;
|
||
ULONG Length;
|
||
STRING MessageHeader;
|
||
|
||
MessageHeader.Length = sizeof(*m);
|
||
MessageHeader.Buffer = (PCHAR)m;
|
||
|
||
Length = AdditionalData->Length;
|
||
|
||
if (((a->TargetBaseAddress + Length) <= sizeof(KPROCESSOR_STATE)) &&
|
||
(m->Processor < (ULONG)KeNumberProcessors)) {
|
||
PKPROCESSOR_STATE ProcessorState = &KdpProcessorState[m->Processor];
|
||
if (a->TargetBaseAddress < sizeof(CONTEXT)) {
|
||
// Need to update the thread context information.
|
||
KdWindbgToSingularityContext(&ProcessorState->ContextFrame, x86Context);
|
||
}
|
||
if (a->TargetBaseAddress + Length > sizeof(CONTEXT)) {
|
||
// Need to update the processor context information.
|
||
KDDBG(" Writing SpecialRegisters.\n");
|
||
ASSERT(m->Processor == 0); // MP support broken.
|
||
|
||
#if 0
|
||
// We don't support separate kernel data breakpoints as
|
||
// Singularity uses a single address space.
|
||
kdprintf(" dr0=%p dr1=%p dr2=%p dr3=%p dr6=%p dr7=%p\n",
|
||
(PVOID)(windbg->Dr0),
|
||
(PVOID)(windbg->Dr1),
|
||
(PVOID)(windbg->Dr2),
|
||
(PVOID)(windbg->Dr3),
|
||
(PVOID)(windbg->Dr6),
|
||
(PVOID)(windbg->Dr7));
|
||
|
||
KSPECIAL_REGISTERS *pksp = &ProcessorState->SpecialRegisters;
|
||
kdprintf(" cr0=%p cr2=%p cr3=%p cr4=%p\n",
|
||
pksp->Cr0, pksp->Cr2, pksp->Cr3, pksp->Cr4);
|
||
|
||
__asm {
|
||
mov ebx, pksp;
|
||
|
||
#if 0
|
||
mov eax, [ebx].Cr0;
|
||
mov cr0, eax;
|
||
mov eax, [ebx].Cr2;
|
||
mov cr2, eax;
|
||
mov eax, [ebx].Cr2;
|
||
mov cr3, eax;
|
||
mov eax, [ebx].Cr4;
|
||
_emit 0x0f; // mov cr4,eax
|
||
_emit 0x22;
|
||
_emit 0xe0;
|
||
#endif
|
||
|
||
mov eax, [ebx].KernelDr0;
|
||
mov dr0, eax;
|
||
mov eax, [ebx].KernelDr1;
|
||
mov dr1, eax;
|
||
mov eax, [ebx].KernelDr2;
|
||
mov dr2, eax;
|
||
mov eax, [ebx].KernelDr3;
|
||
mov dr3, eax;
|
||
mov eax, [ebx].KernelDr6;
|
||
mov dr6, eax;
|
||
mov eax, [ebx].KernelDr7;
|
||
mov dr7, eax;
|
||
}
|
||
kdprintf(" dr0=%p dr1=%p dr2=%p dr3=%p dr6=%p dr7=%p\n",
|
||
(PVOID)(pksp->KernelDr0),
|
||
(PVOID)(pksp->KernelDr1),
|
||
(PVOID)(pksp->KernelDr2),
|
||
(PVOID)(pksp->KernelDr3),
|
||
(PVOID)(pksp->KernelDr6),
|
||
(PVOID)(pksp->KernelDr7));
|
||
kdprintf(" rr0=%p rr1=%p rr2=%p rr3=%p rr6=%p rr7=%p\n",
|
||
(PVOID)(pksp->Reserved[0]),
|
||
(PVOID)(pksp->Reserved[1]),
|
||
(PVOID)(pksp->Reserved[2]),
|
||
(PVOID)(pksp->Reserved[3]),
|
||
(PVOID)(pksp->Reserved[4]),
|
||
(PVOID)(pksp->Reserved[5]));
|
||
#endif
|
||
}
|
||
|
||
m->ReturnStatus = KdpCopyFromPtr(((uint8*)ProcessorState) + a->TargetBaseAddress,
|
||
AdditionalData->Buffer,
|
||
Length,
|
||
&Length);
|
||
} else {
|
||
m->ReturnStatus = STATUS_UNSUCCESSFUL;
|
||
Length = 0;
|
||
}
|
||
|
||
a->ActualBytesWritten = Length;
|
||
|
||
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
&MessageHeader,
|
||
AdditionalData,
|
||
&KdpContext);
|
||
}
|
||
|
||
static
|
||
VOID
|
||
KdpSetContext(
|
||
IN PDBGKD_MANIPULATE_STATE64 m,
|
||
IN PSTRING AdditionalData,
|
||
IN Struct_Microsoft_Singularity_X86_ThreadContext * x86Context
|
||
)
|
||
// 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.
|
||
// x86Context - Supplies the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
STRING MessageHeader;
|
||
|
||
MessageHeader.Length = sizeof(*m);
|
||
MessageHeader.Buffer = (PCHAR)m;
|
||
|
||
ASSERT(AdditionalData->Length == sizeof(CONTEXT));
|
||
|
||
ASSERT(m->Processor == 0); // MP support broken.
|
||
|
||
if ((m->Processor >= (USHORT)KeNumberProcessors) ||
|
||
(KdpContextSent == FALSE)) {
|
||
m->ReturnStatus = STATUS_UNSUCCESSFUL;
|
||
}
|
||
else {
|
||
m->ReturnStatus = STATUS_SUCCESS;
|
||
KdWindbgToSingularityContext((CONTEXT*)AdditionalData->Buffer, x86Context);
|
||
}
|
||
|
||
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
&MessageHeader,
|
||
NULL,
|
||
&KdpContext);
|
||
}
|
||
|
||
static
|
||
VOID
|
||
KdpGetContext(
|
||
IN PDBGKD_MANIPULATE_STATE64 m,
|
||
IN PSTRING AdditionalData,
|
||
IN Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
|
||
)
|
||
// 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.
|
||
// x86Context - Supplies the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
STRING MessageHeader;
|
||
|
||
MessageHeader.Length = sizeof(*m);
|
||
MessageHeader.Buffer = (PCHAR)m;
|
||
|
||
ASSERT(AdditionalData->Length == 0);
|
||
|
||
ASSERT(m->Processor == 0); // MP support broken.
|
||
|
||
if (m->Processor >= (USHORT)KeNumberProcessors) {
|
||
m->ReturnStatus = STATUS_UNSUCCESSFUL;
|
||
}
|
||
else {
|
||
m->ReturnStatus = STATUS_SUCCESS;
|
||
AdditionalData->Length = sizeof(CONTEXT);
|
||
|
||
KdSingularityToWindbgContext(x86Context, (CONTEXT*)AdditionalData->Buffer);
|
||
KdpContextSent = TRUE;
|
||
}
|
||
|
||
KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
&MessageHeader,
|
||
AdditionalData,
|
||
&KdpContext);
|
||
}
|
||
|
||
|
||
ULONG
|
||
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.
|
||
{
|
||
ULONG 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 ULONG Handle
|
||
)
|
||
{
|
||
ULONG 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.
|
||
// x86Context - Supplies the current context.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
PDBGKD_WRITE_BREAKPOINT64 a = &m->u.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.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
PDBGKD_RESTORE_BREAKPOINT a = &m->u.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_X86_ThreadContext *x86Context
|
||
)
|
||
// Routine Description:
|
||
// Extract continuation control data from Manipulate_State message
|
||
//
|
||
// Arguments:
|
||
// ManipulateState - supplies pointer to Manipulate_State packet
|
||
// x86Context - Supplies a pointer to a context record.
|
||
//
|
||
// Return Value:
|
||
// None.
|
||
{
|
||
//PKPRCB Prcb;
|
||
//ULONG Processor;
|
||
|
||
if (NT_SUCCESS(ManipulateState->u.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.
|
||
//
|
||
|
||
if (ManipulateState->u.Continue2.ControlSet.TraceFlag == TRUE) {
|
||
KDDBG2("KD: Warning - trace flag set\n");
|
||
x86Context->efl |= Struct_Microsoft_Singularity_X86_EFlags_TF;
|
||
}
|
||
else {
|
||
x86Context->efl &= ~Struct_Microsoft_Singularity_X86_EFlags_TF;
|
||
}
|
||
|
||
UINT32 _dr7 = ManipulateState->u.Continue2.ControlSet.Dr7;
|
||
x86Context->dr7 = ManipulateState->u.Continue2.ControlSet.Dr7;
|
||
|
||
#if 0
|
||
__asm {
|
||
mov eax, 0;
|
||
mov dr6, eax;
|
||
mov eax, _dr7;
|
||
mov dr7, eax;
|
||
}
|
||
#endif
|
||
#if 0
|
||
for (Processor = 0; Processor < (ULONG)KeNumberProcessors; Processor++) {
|
||
Prcb = KiProcessorBlock[Processor];
|
||
|
||
Prcb->ProcessorState.SpecialRegisters.KernelDr7 =
|
||
ManipulateState->u.Continue2.ControlSet.Dr7;
|
||
|
||
Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0L;
|
||
}
|
||
if (ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart != 1) {
|
||
KdpCurrentSymbolStart = ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart;
|
||
KdpCurrentSymbolEnd = ManipulateState->u.Continue2.ControlSet.CurrentSymbolEnd;
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|
||
KCONTINUE_STATUS
|
||
KdpSendWaitContinue(
|
||
IN ULONG OutPacketType,
|
||
IN PSTRING OutMessageHeader,
|
||
IN PSTRING OutMessageData OPTIONAL,
|
||
IN OUT Struct_Microsoft_Singularity_X86_ThreadContext *x86Context
|
||
)
|
||
// 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.
|
||
{
|
||
|
||
ULONG Length;
|
||
STRING MessageData;
|
||
STRING MessageHeader;
|
||
DBGKD_MANIPULATE_STATE64 ManipulateState;
|
||
ULONG 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.
|
||
//
|
||
|
||
KDDBG("KdpSendWait::\r");
|
||
|
||
do {
|
||
ReturnCode = KdReceivePacket(
|
||
PACKET_TYPE_KD_STATE_MANIPULATE,
|
||
&MessageHeader,
|
||
&MessageData,
|
||
&Length,
|
||
&KdpContext
|
||
);
|
||
KDDBG2("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("KdpSendWait::KdReadVirtualMemory (%8p..%8p) (%d bytes)\n",
|
||
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress,
|
||
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress +
|
||
ManipulateState.u.ReadMemory.TransferCount,
|
||
ManipulateState.u.ReadMemory.TransferCount);
|
||
KdpReadVirtualMemory(&ManipulateState,&MessageData);
|
||
break;
|
||
|
||
#if 0
|
||
case DbgKdReadVirtualMemory64Api:
|
||
KdpReadVirtualMemory64(&ManipulateState,&MessageData);
|
||
break;
|
||
#endif
|
||
case DbgKdWriteVirtualMemoryApi:
|
||
KDDBG("KdpSendWait::KdWriteVirtualMemory(%8p..%8p)\n",
|
||
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress,
|
||
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress +
|
||
ManipulateState.u.WriteMemory.TransferCount);
|
||
KdpWriteVirtualMemory(&ManipulateState,&MessageData);
|
||
break;
|
||
#if 0
|
||
case DbgKdWriteVirtualMemory64Api:
|
||
KdpWriteVirtualMemory64(&ManipulateState,&MessageData);
|
||
break;
|
||
#endif
|
||
case DbgKdGetVersionApi:
|
||
KDDBG("KdpSendWait::KdGetVersion()\n");
|
||
KdpGetVersion(&ManipulateState);
|
||
break;
|
||
|
||
case DbgKdGetContextApi:
|
||
KDDBG("KdpSendWait::KdGetContext(p=%x)\n", ManipulateState.Processor);
|
||
KdpGetContext(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdReadControlSpaceApi:
|
||
KDDBG("KdpSendWait::KdReadControlSpace (%8p..%8p p=%x)\n",
|
||
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress,
|
||
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress +
|
||
ManipulateState.u.ReadMemory.TransferCount,
|
||
(ULONG_PTR)ManipulateState.Processor);
|
||
KdpReadControlSpace(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdWriteControlSpaceApi:
|
||
KDDBG("KdpSendWait::KdWriteControlSpace (%8p..%8p p=%x)\n",
|
||
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress,
|
||
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress +
|
||
ManipulateState.u.WriteMemory.TransferCount,
|
||
(ULONG_PTR)ManipulateState.Processor);
|
||
KdpWriteControlSpace(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdSetContextApi:
|
||
KDDBG("KdpSendWait::KdSetContext(p=%x)\n", ManipulateState.Processor);
|
||
KdpSetContext(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdWriteBreakPointApi:
|
||
KDDBG("KdpSendWait::KdWriteBreakPoint(%p)\n",
|
||
ManipulateState.u.WriteBreakPoint.BreakPointAddress);
|
||
KdpWriteBreakpoint(&ManipulateState);
|
||
break;
|
||
|
||
case DbgKdRestoreBreakPointApi:
|
||
if (ManipulateState.u.RestoreBreakPoint.BreakPointHandle < 0x8 ||
|
||
ManipulateState.u.RestoreBreakPoint.BreakPointHandle > 0x1e) {
|
||
KDDBG("KdpSendWait::KdRestoreBreakpoint(h=%x)\n",
|
||
ManipulateState.u.RestoreBreakPoint.BreakPointHandle);
|
||
}
|
||
KdpRestoreBreakpoint(&ManipulateState,&MessageData);
|
||
break;
|
||
|
||
case DbgKdContinueApi:
|
||
KDDBG("KdpSendWait::KdContinue(ContinueStatus=%08x)\n",
|
||
ManipulateState.u.Continue.ContinueStatus);
|
||
if (NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus)) {
|
||
return ContinueSuccess;
|
||
}
|
||
else {
|
||
return ContinueError;
|
||
}
|
||
break;
|
||
|
||
case DbgKdContinueApi2:
|
||
KDDBG("KdpSendWait::KdContinue2(ContinueStatus=%08x)\n",
|
||
ManipulateState.u.Continue2.ContinueStatus);
|
||
if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus)) {
|
||
KDDBG("KdpSendWait::KdpGetStateChange()\n");
|
||
KdpGetStateChange(&ManipulateState,x86Context);
|
||
return ContinueSuccess;
|
||
}
|
||
else {
|
||
KDDBG("KdpSendWait::ContinueError!\n");
|
||
return ContinueError;
|
||
}
|
||
break;
|
||
|
||
case DbgKdReadPhysicalMemoryApi:
|
||
KDDBG("KdpSendWait::KdReadPhysicalMemory (%8p..%8p)\n",
|
||
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress,
|
||
(ULONG_PTR)ManipulateState.u.ReadMemory.TargetBaseAddress +
|
||
ManipulateState.u.ReadMemory.TransferCount);
|
||
// KdpReadPhysicalMemory(&ManipulateState,&MessageData,x86Context);
|
||
KdpReadPhysicalMemory(&ManipulateState,&MessageData);
|
||
break;
|
||
|
||
case DbgKdWritePhysicalMemoryApi:
|
||
KdpWritePhysicalMemory(&ManipulateState,&MessageData);
|
||
KDDBG("KdpSendWait::KdWritePhysicalMemory (%8p..%8p)\n",
|
||
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress,
|
||
(ULONG_PTR)ManipulateState.u.WriteMemory.TargetBaseAddress +
|
||
ManipulateState.u.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,x86Context);
|
||
break;
|
||
|
||
case DbgKdWriteMachineSpecificRegister:
|
||
KdpWriteMachineSpecificRegister(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
#if 0 // Haven't implemented most of the protocol yet!
|
||
case DbgKdCheckLowMemoryApi:
|
||
KdpCheckLowMemory (&ManipulateState);
|
||
break;
|
||
|
||
case DbgKdReadControlSpaceApi:
|
||
KdpReadControlSpace(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdWriteControlSpaceApi:
|
||
KdpWriteControlSpace(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdReadIoSpaceApi:
|
||
KdpReadIoSpace(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdWriteIoSpaceApi:
|
||
KdpWriteIoSpace(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdReadIoSpaceExtendedApi:
|
||
KdpReadIoSpaceExtended(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdWriteIoSpaceExtendedApi:
|
||
KdpWriteIoSpaceExtended(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdGetBusDataApi:
|
||
KdpGetBusData(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdSetBusDataApi:
|
||
KdpSetBusData(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdRebootApi:
|
||
HalReturnToFirmware(HalRebootRoutine);
|
||
break;
|
||
|
||
#if defined(i386)
|
||
case DbgKdSetSpecialCallApi:
|
||
KdSetSpecialCall(&ManipulateState,x86Context);
|
||
break;
|
||
|
||
case DbgKdClearSpecialCallsApi:
|
||
KdClearSpecialCalls();
|
||
break;
|
||
|
||
case DbgKdSetInternalBreakPointApi:
|
||
KdSetInternalBreakpoint(&ManipulateState);
|
||
break;
|
||
|
||
case DbgKdGetInternalBreakPointApi:
|
||
KdGetInternalBreakpoint(&ManipulateState);
|
||
break;
|
||
|
||
case DbgKdClearAllInternalBreakpointsApi:
|
||
KdpNumInternalBreakpoints = 0;
|
||
break;
|
||
|
||
#endif // i386
|
||
|
||
case DbgKdCauseBugCheckApi:
|
||
KdpCauseBugCheck(&ManipulateState);
|
||
break;
|
||
|
||
case DbgKdPageInApi:
|
||
KdpNotSupported(&ManipulateState);
|
||
break;
|
||
|
||
case DbgKdWriteBreakPointExApi:
|
||
Status = KdpWriteBreakPointEx(&ManipulateState,
|
||
&MessageData,
|
||
x86Context);
|
||
if (Status) {
|
||
ManipulateState.ApiNumber = DbgKdContinueApi;
|
||
ManipulateState.u.Continue.ContinueStatus = Status;
|
||
return ContinueError;
|
||
}
|
||
break;
|
||
|
||
case DbgKdRestoreBreakPointExApi:
|
||
KdpRestoreBreakPointEx(&ManipulateState,&MessageData,x86Context);
|
||
break;
|
||
|
||
case DbgKdSearchMemoryApi:
|
||
KdpSearchMemory(&ManipulateState, &MessageData, x86Context);
|
||
break;
|
||
|
||
case DbgKdFillMemoryApi:
|
||
KdpFillMemory(&ManipulateState, &MessageData, x86Context);
|
||
break;
|
||
|
||
case DbgKdQueryMemoryApi:
|
||
KdpQueryMemory(&ManipulateState, x86Context);
|
||
break;
|
||
|
||
//
|
||
// Invalid message.
|
||
//
|
||
#endif // XXX Haven't implemented most of the protocol yet!
|
||
|
||
default:
|
||
kdprintf("KdpSendWaitContinue: unrecognized API number 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.
|
||
{
|
||
|
||
ULONG 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 = (USHORT)GetCurrentProcessorNumber();
|
||
DebugIo.u.PrintString.LengthOfString = Length;
|
||
MessageHeader.Length = sizeof(DBGKD_DEBUG_IO);
|
||
MessageHeader.Buffer = (PCHAR)&DebugIo;
|
||
|
||
// Construct the print string data and data descriptor.
|
||
//
|
||
MessageData.Length = (USHORT)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;
|
||
}
|
||
|
||
|
||
// This should be fixed.
|
||
VOID
|
||
KdPutChar(
|
||
CHAR c
|
||
)
|
||
{
|
||
static char _KdpDebugStringBuf[KDP_MESSAGE_BUFFER_SIZE];
|
||
static STRING KdpDebugString = { 0, KDP_MESSAGE_BUFFER_SIZE, (PCHAR)&_KdpDebugStringBuf };
|
||
|
||
if (KdpInDebugger) {
|
||
koutput(NULL, c);
|
||
return;
|
||
}
|
||
|
||
KdpDebugString.Buffer[KdpDebugString.Length++] = c;
|
||
if (c == '\n' || KdpDebugString.Length == KdpDebugString.MaximumLength) {
|
||
KdPrintString(&KdpDebugString, FALSE);
|
||
KdpDebugString.Length = 0;
|
||
}
|
||
}
|
||
|
||
/////////////////////////////////////////////////////// Methods Exposed to C#.
|
||
//
|
||
bool Class_Microsoft_Singularity_DebugStub::
|
||
g_Trap(Struct_Microsoft_Singularity_X86_ThreadContext *context, bool firstChance)
|
||
{
|
||
EXCEPTION_RECORD64 er;
|
||
bool handled;
|
||
RtlZeroMemory(&er, sizeof(er));
|
||
|
||
KdpLock();
|
||
|
||
// Breakpoints:
|
||
switch (context->num) {
|
||
|
||
case Struct_Microsoft_Singularity_X86_EVectors_SingleStep:
|
||
er.ExceptionCode = STATUS_SINGLE_STEP;
|
||
er.ExceptionAddress = (ULONG64)context->eip;
|
||
// context->efl &= ~Struct_Microsoft_Singularity_X86_EFlags_TF;
|
||
break;
|
||
|
||
case Struct_Microsoft_Singularity_X86_EVectors_Breakpoint:
|
||
context->eip -= 1;
|
||
er.ExceptionCode = STATUS_BREAKPOINT;
|
||
er.NumberParameters = 1;
|
||
er.ExceptionInformation[0] = BREAKPOINT_BREAK;
|
||
er.ExceptionAddress = (ULONG64)context->eip;
|
||
break;
|
||
|
||
case Struct_Microsoft_Singularity_X86_EVectors_IllegalInstruction:
|
||
er.ExceptionCode = STATUS_ILLEGAL_INSTRUCTION;
|
||
break;
|
||
|
||
case Struct_Microsoft_Singularity_X86_EVectors_PageFault:
|
||
KDDBG("KD: 0x0E %d\n", context->num);
|
||
er.ExceptionCode = STATUS_ACCESS_VIOLATION;
|
||
er.ExceptionAddress = (UINT64)context->eip;
|
||
er.NumberParameters = 1;
|
||
er.ExceptionInformation[0] = context->cr2;
|
||
break;
|
||
|
||
case Struct_Microsoft_Singularity_X86_EVectors_FirstChanceException: {
|
||
KdDebugTrapData *trapData = (KdDebugTrapData *) (context->eax);
|
||
switch(trapData->tag) {
|
||
case KdDebugTrapData::FIRST_CHANCE_EXCEPTION:
|
||
context->eax = trapData->u.firstChanceException.throwAddr;
|
||
KDDBG("KD: First chance C# exception\n");
|
||
// er.ExceptionCode = STATUS_CPP_EH_EXCEPTION; //0xe06d7363;
|
||
er.ExceptionCode = STATUS_VCPP_EXCEPTION; //0x8000ff1f;
|
||
er.ExceptionAddress = (UINT64)context->eip;
|
||
er.NumberParameters = 1;
|
||
er.ExceptionInformation[0] = BREAKPOINT_BREAK;
|
||
break;
|
||
case KdDebugTrapData::LOADED_BINARY:
|
||
KDDBG("KD: Loaded binary\n");
|
||
KdpUnlock();
|
||
LoadedBinary(context);
|
||
return true;
|
||
case KdDebugTrapData::UNLOADED_BINARY:
|
||
KDDBG("KD: Unloaded binary\n");
|
||
KdpUnlock();
|
||
UnloadedBinary(context);
|
||
return true;
|
||
default:
|
||
KDDBG("KD: Unexpected interrupt %d\n", context->num);
|
||
er.ExceptionCode = 0x80000000 + context->num;
|
||
er.ExceptionAddress = (UINT64)context->eip;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
|
||
case Struct_Microsoft_Singularity_X86_EVectors_SecondChanceException:
|
||
KDDBG("KD: Second chance C# exception\n");
|
||
er.ExceptionCode = STATUS_VCPP_EXCEPTION;
|
||
er.ExceptionAddress = (UINT64)context->eip;
|
||
break;
|
||
|
||
case Struct_Microsoft_Singularity_X86_EVectors_DebuggerBreakRequest:
|
||
KDDBG("KD: Debugger ctrl-break\n");
|
||
er.ExceptionCode = STATUS_BREAKPOINT;
|
||
er.ExceptionInformation[0] = BREAKPOINT_BREAK;
|
||
er.ExceptionAddress = (UINT64)context->eip;
|
||
break;
|
||
|
||
default:
|
||
KDDBG("KD: Unexpected interrupt %d\n", context->num);
|
||
er.ExceptionCode = 0x80000000 + context->num;
|
||
er.ExceptionAddress = (UINT64)context->eip;
|
||
break;
|
||
|
||
}
|
||
|
||
KDDBG("Trap: Context at %p\n", context);
|
||
KDDBG(" CXT=%08x THR=%08x\n",
|
||
context, context->_thread);
|
||
KDDBG(" EIP=%08x EFL=%08x ERR=%08x CR2=%08x\n",
|
||
context->eip, context->efl, context->err, context->cr2);
|
||
KDDBG(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n",
|
||
context->eax, context->ebx, context->ecx, context->edx);
|
||
KDDBG(" ESP=%08x EBP=%08x ESI=%08x EDI=%08x\n",
|
||
context->esp, context->ebp, context->esi, context->edi);
|
||
|
||
#if 0
|
||
kdprintf("Exception EIPs = %08x", er.ExceptionAddress);
|
||
uintptr ebp = context->ebp;
|
||
for (int i = 0; i < 3 && ebp >= Struct_Microsoft_Singularity_BootInfo_PHYSICAL_DISABLED; i++) {
|
||
|
||
uintptr next = ((uintptr *)ebp)[0];
|
||
uintptr code = ((uintptr *)ebp)[1];
|
||
|
||
kdprintf(" %08x", code);
|
||
ebp = next;
|
||
}
|
||
kdprintf("\n");
|
||
#endif
|
||
|
||
KdpEnter();
|
||
|
||
handled = (KdpReportExceptionStateChange(&er, context, firstChance) == ContinueSuccess);
|
||
if (context->num == Struct_Microsoft_Singularity_X86_EVectors_SingleStep &&
|
||
(context->efl & Struct_Microsoft_Singularity_X86_EFlags_TF) == 0) {
|
||
#if 0
|
||
kdprintf("Continuing to eip=%08x [efl=%08x]\n", context->eip, context->efl);
|
||
#endif
|
||
|
||
#if 0
|
||
if (context->eip != 0 && *(uint8*)(context->eip) == 0x9c) {
|
||
// we always override into single-step mode if the next instruction is pushfd.
|
||
context->efl |= Struct_Microsoft_Singularity_X86_EFlags_TF;
|
||
kdprintf("Continuing to eip=%08x [efl=%08x] ****\n", context->eip, context->efl);
|
||
#if 0
|
||
kdprintf(" CXT=%08x THR=%08x REG=%02x\n",
|
||
context, context->_thread, context->regs);
|
||
kdprintf(" EIP=%08x EFL=%08x ERR=%08x CR2=%08x\n",
|
||
context->eip, context->efl, context->err, context->cr2);
|
||
kdprintf(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n",
|
||
context->eax, context->ebx, context->ecx, context->edx);
|
||
kdprintf(" ESP=%08x EBP=%08x ESI=%08x EDI=%08x\n",
|
||
context->esp, context->ebp, context->esi, context->edi);
|
||
kdprintf(" DR0=%08x DR1=%08x DR2=%08x DR3=%08x\n",
|
||
context->dr0, context->dr1, context->dr2, context->dr3);
|
||
kdprintf(" DR6=%08x DR7=%08x DR2=%08x DR3=%08x\n",
|
||
context->dr6, context->dr7, context->dr2, context->dr3);
|
||
#endif
|
||
}
|
||
#endif
|
||
}
|
||
|
||
#if 0
|
||
if (context->num == Struct_Microsoft_Singularity_X86_EVectors_SingleStep &&
|
||
context->eip != 0 && *(uint8*)(context->eip) == 0x9c) {
|
||
kdprintf(" CXT=%08x THR=%08x REG=%02x\n",
|
||
context, context->_thread, context->regs);
|
||
kdprintf(" EIP=%08x EFL=%08x ERR=%08x CR2=%08x\n",
|
||
context->eip, context->efl, context->err, context->cr2);
|
||
kdprintf(" EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n",
|
||
context->eax, context->ebx, context->ecx, context->edx);
|
||
kdprintf(" ESP=%08x EBP=%08x ESI=%08x EDI=%08x\n",
|
||
context->esp, context->ebp, context->esi, context->edi);
|
||
kdprintf(" DR0=%08x DR1=%08x DR2=%08x DR3=%08x\n",
|
||
context->dr0, context->dr1, context->dr2, context->dr3);
|
||
kdprintf(" DR6=%08x DR7=%08x DR2=%08x DR3=%08x\n",
|
||
context->dr6, context->dr7, context->dr2, context->dr3);
|
||
}
|
||
kdprintf("-- Trap num=0x%02x eip=%08x\n", context->num, context->eip);
|
||
#endif
|
||
|
||
KdpLeave();
|
||
|
||
KdpUnlock();
|
||
|
||
return handled;
|
||
}
|
||
|
||
bool Class_Microsoft_Singularity_DebugStub::
|
||
g_TrapForProcessorSwitch(Struct_Microsoft_Singularity_X86_ThreadContext *context)
|
||
{
|
||
EXCEPTION_RECORD64 er;
|
||
|
||
RtlZeroMemory(&er, sizeof(er));
|
||
er.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER;
|
||
er.ExceptionRecord = (ULONG64)&er;
|
||
er.ExceptionAddress = (ULONG64)context->eip;
|
||
|
||
// KdSave(FALSE);
|
||
KCONTINUE_STATUS status = KdpReportExceptionStateChange(&er, context, true);
|
||
// KdRestore(FALSE);
|
||
return status == ContinueSuccess;
|
||
}
|
||
|
||
void Class_Microsoft_Singularity_DebugStub::g_AddProcessor(int cpuId)
|
||
{
|
||
KdpLock();
|
||
KeNumberProcessors = cpuId + 1;
|
||
KdpUnlock();
|
||
}
|
||
|
||
void Class_Microsoft_Singularity_DebugStub::g_RevertToUniprocessor()
|
||
{
|
||
KdpLock();
|
||
KeNumberProcessors = 1;
|
||
KdpUnlock();
|
||
}
|
||
|
||
bool Class_Microsoft_Singularity_DebugStub::g_PollForBreak()
|
||
{
|
||
// KdpLock();
|
||
|
||
// 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;
|
||
}
|
||
|
||
bool success = KdPollBreakIn();
|
||
// KdpUnlock();
|
||
return success;
|
||
}
|
||
|
||
void Class_Microsoft_Singularity_DebugStub::g_Break()
|
||
{
|
||
__asm int 3;
|
||
}
|
||
|
||
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)
|
||
{
|
||
KdDebugTrapData trapData, *trapDataPtr = &trapData;
|
||
trapData.tag = KdDebugTrapData::LOADED_BINARY;
|
||
trapData.u.loadedBinary.baseAddress = baseAddress;
|
||
trapData.u.loadedBinary.bytes = bytes;
|
||
trapData.u.loadedBinary.name = name;
|
||
trapData.u.loadedBinary.checksum = checksum;
|
||
trapData.u.loadedBinary.timestamp = timestamp;
|
||
trapData.u.loadedBinary.silent = silent;
|
||
|
||
// Call LoadedBinary via an __asm int 29:
|
||
__asm {
|
||
mov eax, trapDataPtr;
|
||
int 29;
|
||
}
|
||
|
||
return trapData.u.loadedBinary.ret;
|
||
}
|
||
|
||
static void LoadedBinary(Struct_Microsoft_Singularity_X86_ThreadContext *context)
|
||
{
|
||
KdDebugTrapData *trapData = (KdDebugTrapData *) (context->eax);
|
||
UIntPtr baseAddress = trapData->u.loadedBinary.baseAddress;
|
||
UIntPtr bytes = trapData->u.loadedBinary.bytes;
|
||
UIntPtr nameof = trapData->u.loadedBinary.name;
|
||
uint32 checksum = trapData->u.loadedBinary.checksum;
|
||
uint32 timestamp = trapData->u.loadedBinary.timestamp;
|
||
bool silent = trapData->u.loadedBinary.silent;
|
||
|
||
KLDR_DATA_TABLE_ENTRY_WITH_NAME *pEntry;
|
||
bool good = false;
|
||
WCHAR * name = trim((WCHAR *)nameof);
|
||
USHORT nlen = (USHORT)2 * wcslen(name);
|
||
if (nlen > sizeof(pEntry->wzName)) {
|
||
nlen = sizeof(pEntry->wzName);
|
||
}
|
||
|
||
KdpLock();
|
||
#if 0 // Debug module names
|
||
if (name != NULL) {
|
||
kdprintf("LoadedBinary(%08lx: %ls)\n", (uint64)(uintptr)name, name);
|
||
}
|
||
else {
|
||
kdprintf("LoadedBinary(%08lx)\n", (uint64)(uintptr)name);
|
||
}
|
||
#endif
|
||
|
||
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 = (uintptr)bytes;
|
||
memcpy(pEntry->wzName, name, nlen);
|
||
RtlInitUnicodeString(&pEntry->FullDllName, name, nlen);
|
||
RtlInitUnicodeString(&pEntry->BaseDllName, name, nlen);
|
||
|
||
#if 0
|
||
printf("----: BaseOfImage %8lx SizeOfImage %8x ModuleName %8x\n",
|
||
(uint64)(uintptr)baseAddress,
|
||
(uintptr)bytes,
|
||
(uintptr)pEntry->BaseDllName.Buffer);
|
||
printf(" ModuleName: %ls (%p)\n",
|
||
pEntry->BaseDllName.Buffer,
|
||
pEntry);
|
||
#endif
|
||
|
||
// 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,
|
||
(ULONG64)baseAddress,
|
||
(ULONG)0,
|
||
checksum,
|
||
(LONG)bytes,
|
||
FALSE,
|
||
context);
|
||
}
|
||
else {
|
||
KdpReportLoadSymbolsStateChange(NULL,
|
||
0,
|
||
(ULONG64)baseAddress,
|
||
(ULONG)0,
|
||
checksum,
|
||
(LONG)bytes,
|
||
FALSE,
|
||
context);
|
||
}
|
||
}
|
||
KdpUnlock();
|
||
|
||
trapData->u.loadedBinary.ret = good;
|
||
}
|
||
|
||
bool Class_Microsoft_Singularity_DebugStub::
|
||
g_UnloadedBinary(UIntPtr baseAddress, bool silent)
|
||
{
|
||
KdDebugTrapData trapData, *trapDataPtr = &trapData;
|
||
trapData.tag = KdDebugTrapData::UNLOADED_BINARY;
|
||
trapData.u.unloadedBinary.baseAddress = baseAddress;
|
||
trapData.u.unloadedBinary.silent = silent;
|
||
|
||
// Call UnloadedBinary via an __asm int 29:
|
||
__asm {
|
||
mov eax, trapDataPtr;
|
||
int 29;
|
||
}
|
||
|
||
return trapData.u.unloadedBinary.ret;
|
||
}
|
||
|
||
static void UnloadedBinary(Struct_Microsoft_Singularity_X86_ThreadContext *context)
|
||
{
|
||
KdDebugTrapData *trapData = (KdDebugTrapData *) (context->eax);
|
||
UIntPtr baseAddress = trapData->u.unloadedBinary.baseAddress;
|
||
bool silent = trapData->u.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,
|
||
(ULONG64)baseAddress,
|
||
(ULONG)0,
|
||
0,
|
||
0,
|
||
TRUE,
|
||
context);
|
||
}
|
||
RtlZeroMemory(pEntry, sizeof(*pEntry));
|
||
}
|
||
KdpUnlock();
|
||
|
||
trapData->u.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) {
|
||
*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) {
|
||
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 = (USHORT)GetCurrentProcessorNumber();
|
||
DebugIo.u.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 = (USHORT)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)
|
||
{
|
||
if (KdDebuggerNotPresent) {
|
||
return;
|
||
}
|
||
|
||
WCHAR *buffer;
|
||
int length;
|
||
|
||
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);
|
||
}
|
||
|
||
//
|
||
///////////////////////////////////////////////////////////////// End of File.
|