|
|
/*++
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; }
|