windows-nt/Source/XPSP1/NT/base/boot/bd/message.c

492 lines
14 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
message.c
Abstract:
This module implements the debugger state change message functions.
Author:
Mark Lucovsky (markl) 31-Aug-1990
Revision History:
--*/
#include "bd.h"
#if ACCASM && !defined(_MSC_VER)
long asm(const char *,...);
#pragma intrinsic(asm)
#endif
KCONTINUE_STATUS
BdSendWaitContinue (
IN ULONG OutPacketType,
IN PSTRING OutMessageHeader,
IN PSTRING OutMessageData OPTIONAL,
IN OUT PCONTEXT ContextRecord
)
/*++
Routine Description:
This function sends a packet and waits for a continue message. BreakIns
received while waiting will always cause a resend of the packet originally
sent out. While waiting state 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.
ContextRecord - 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 = BD_MESSAGE_BUFFER_SIZE;
MessageData.Buffer = (PCHAR)(&BdMessageBuffer[0]);
//
// Send event notification packet to debugger on host. Come back here
// any time we see a breakin sequence.
//
ResendPacket:
BdSendPacket(OutPacketType,
OutMessageHeader,
OutMessageData);
//
// 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
// BdSendPacket will never stop.
//
if (BdDebuggerNotPresent != FALSE) {
return ContinueSuccess;
}
while (TRUE) {
//
// Wait for State Manipulate Packet without timeout.
//
do {
ReturnCode = BdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
&MessageData,
&Length);
if (ReturnCode == (USHORT)BD_PACKET_RESEND) {
goto ResendPacket;
}
} while (ReturnCode == BD_PACKET_TIMEOUT);
//
// Switch on the return message API number.
//
// BlPrint("BdSendWait: api number %d\n", ManipulateState.ApiNumber);
switch (ManipulateState.ApiNumber) {
case DbgKdReadVirtualMemoryApi:
BdReadVirtualMemory(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdWriteVirtualMemoryApi:
BdWriteVirtualMemory(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdReadPhysicalMemoryApi:
BdReadPhysicalMemory(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdWritePhysicalMemoryApi:
BdWritePhysicalMemory(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdGetContextApi:
BdGetContext(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdSetContextApi:
BdSetContext(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdWriteBreakPointApi:
BdWriteBreakpoint(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdRestoreBreakPointApi:
BdRestoreBreakpoint(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdReadControlSpaceApi:
BdReadControlSpace(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdWriteControlSpaceApi:
BdWriteControlSpace(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdReadIoSpaceApi:
BdReadIoSpace(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdWriteIoSpaceApi:
BdWriteIoSpace(&ManipulateState, &MessageData, ContextRecord);
break;
#if defined(_ALPHA_) || defined(_AXP64_)
case DbgKdReadIoSpaceExtendedApi:
BdReadIoSpaceExtended(&ManipulateState, &MessageData, ContextRecord);
break;
case DbgKdWriteIoSpaceExtendedApi:
BdWriteIoSpaceExtended(&ManipulateState, &MessageData, ContextRecord);
break;
#endif
case DbgKdContinueApi:
if (NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus) != FALSE) {
return ContinueSuccess;
} else {
return ContinueError;
}
break;
case DbgKdContinueApi2:
if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus) != FALSE) {
BdGetStateChange(&ManipulateState, ContextRecord);
return ContinueSuccess;
} else {
return ContinueError;
}
break;
case DbgKdRebootApi:
BdReboot();
break;
case DbgKdGetVersionApi:
BdGetVersion(&ManipulateState);
break;
case DbgKdWriteBreakPointExApi:
Status = BdWriteBreakPointEx(&ManipulateState,
&MessageData,
ContextRecord);
if (Status) {
ManipulateState.ApiNumber = DbgKdContinueApi;
ManipulateState.u.Continue.ContinueStatus = Status;
return ContinueError;
}
break;
case DbgKdRestoreBreakPointExApi:
BdRestoreBreakPointEx(&ManipulateState, &MessageData, ContextRecord);
break;
//
// Invalid message.
//
default:
MessageData.Length = 0;
ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
BdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
&MessageHeader,
&MessageData);
break;
}
#ifdef _ALPHA_
//
//jnfix
// this is embarrasing, we have an icache coherency problem that
// the following imb fixes, later we must track this down to the
// exact offending API but for now this statement allows the stub
// work to appropriately for Alpha.
//
#if defined(_MSC_VER)
__PAL_IMB();
#else
asm( "call_pal 0x86" ); // x86 = imb
#endif
#endif
}
}
VOID
BdpSetCommonState(
IN ULONG NewState,
IN PCONTEXT ContextRecord,
OUT PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange
)
{
BOOLEAN DeletedBps;
PCHAR PcMemory;
USHORT InstrCount;
PUCHAR InstrStream;
WaitStateChange->NewState = NewState;
WaitStateChange->ProcessorLevel = 0;
WaitStateChange->Processor = 0;
WaitStateChange->NumberProcessors = 1;
WaitStateChange->Thread = 0;
PcMemory = (PCHAR)CONTEXT_TO_PROGRAM_COUNTER(ContextRecord);
WaitStateChange->ProgramCounter = (ULONG64)(LONG64)(LONG_PTR)PcMemory;
RtlZeroMemory(&WaitStateChange->AnyControlReport,
sizeof(WaitStateChange->AnyControlReport));
//
// Copy instruction stream immediately following location of event.
//
InstrStream = WaitStateChange->ControlReport.InstructionStream;
InstrCount = (USHORT)
BdMoveMemory(InstrStream, PcMemory, DBGKD_MAXSTREAM);
WaitStateChange->ControlReport.InstructionCount = InstrCount;
//
// Clear breakpoints in copied area.
// If there were any breakpoints cleared, recopy the instruction area
// without them.
//
if (BdDeleteBreakpointRange((ULONG_PTR)PcMemory,
(ULONG_PTR)PcMemory + InstrCount - 1)) {
BdMoveMemory(InstrStream, PcMemory, InstrCount);
}
}
LOGICAL
BdReportExceptionStateChange (
IN PEXCEPTION_RECORD ExceptionRecord,
IN OUT PCONTEXT ContextRecord
)
/*++
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.
ContextRecord - Supplies a pointer to a context record.
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;
do {
//
// Construct the wait state change message and message descriptor.
//
BdpSetCommonState(DbgKdExceptionStateChange, ContextRecord,
&WaitStateChange);
if (sizeof(EXCEPTION_RECORD) ==
sizeof(WaitStateChange.u.Exception.ExceptionRecord)) {
BdCopyMemory((PCHAR)&WaitStateChange.u.Exception.ExceptionRecord,
(PCHAR)ExceptionRecord,
sizeof(EXCEPTION_RECORD));
} else {
ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
&WaitStateChange.u.Exception.ExceptionRecord);
}
WaitStateChange.u.Exception.FirstChance = TRUE;
BdSetStateChange(&WaitStateChange,
ExceptionRecord,
ContextRecord);
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 = BdSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
&MessageHeader,
&MessageData,
ContextRecord);
} while (Status == ContinueProcessorReselected) ;
return (BOOLEAN) Status;
}
LOGICAL
BdReportLoadSymbolsStateChange (
IN PSTRING PathName,
IN PKD_SYMBOLS_INFO SymbolInfo,
IN LOGICAL UnloadSymbols,
IN OUT PCONTEXT ContextRecord
)
/*++
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 32-bit identifier for process that is using
the symbols. -1 for system process.
CheckSum - Unique 32-bit identifier 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.
--*/
{
PSTRING AdditionalData;
STRING MessageData;
STRING MessageHeader;
DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
KCONTINUE_STATUS Status;
do {
//
// Construct the wait state change message and message descriptor.
//
BdpSetCommonState(DbgKdLoadSymbolsStateChange, ContextRecord,
&WaitStateChange);
BdSetContextState(&WaitStateChange, ContextRecord);
WaitStateChange.u.LoadSymbols.UnloadSymbols = (BOOLEAN)UnloadSymbols;
WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG64)SymbolInfo->BaseOfDll;
WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
if (ARGUMENT_PRESENT(PathName)) {
WaitStateChange.u.LoadSymbols.PathNameLength =
BdMoveMemory((PCHAR)BdMessageBuffer,
(PCHAR)PathName->Buffer,
PathName->Length) + 1;
MessageData.Buffer = (PCHAR)(&BdMessageBuffer[0]);
MessageData.Length = (USHORT)WaitStateChange.u.LoadSymbols.PathNameLength;
MessageData.Buffer[MessageData.Length-1] = '\0';
AdditionalData = &MessageData;
} else {
WaitStateChange.u.LoadSymbols.PathNameLength = 0;
AdditionalData = NULL;
}
MessageHeader.Length = sizeof(WaitStateChange);
MessageHeader.Buffer = (PCHAR)&WaitStateChange;
//
// Send packet to the kernel debugger on the host machine, wait
// for the reply.
//
Status = BdSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
&MessageHeader,
AdditionalData,
ContextRecord);
} while (Status == ContinueProcessorReselected);
return (BOOLEAN) Status;
}