2703 lines
85 KiB
C++
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.
|