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