/*++ Copyright (c) 1990 Microsoft Corporation Module Name: api.c Abstract: This module implements the all apis that simulate their WIN32 counterparts. Author: Wesley Witt (wesw) 8-Mar-1992 Environment: NT 3.1 --*/ #include "precomp.h" #pragma hdrstop extern CRITICAL_SECTION csPacket; extern USHORT ContextSize; //#define dp(s) OutputDebugString(s) #define dp(s) DWORD DmKdReadPhysicalMemory( IN ULONG64 TargetBaseAddress, OUT PVOID UserInterfaceBuffer, IN ULONG TransferCount, OUT PULONG ActualBytesRead OPTIONAL ) /*++ Routine Description: This function reads the specified data from the physical memory of the system being debugged. Arguments: TargetBaseAddress - Supplies the physical address of the memory to read from the system being debugged. UserInterfaceBuffer - Supplies the address of the buffer in the user interface that data read is to be placed. TransferCount - Specifies the number of bytes to read. ActualBytesRead - An optional parameter that if supplied, returns the number of bytes actually read. Return Value: STATUS_SUCCESS - The specified read occured. STATUS_BUFFER_OVERFLOW - A read that is too large was specified. STATUS_ACCESS_VIOLATION - TBD // Can you even HAVE an access // violation with a physical // memory access?? !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_READ_MEMORY64 a = &m64.u.ReadMemory; PDBGKD_READ_MEMORY32 a32 = &m32.u.ReadMemory; PDBGKD_MANIPULATE_STATE64 Reply; DWORD st, cb, cb2; BOOL rc; assert( Is64PtrSE(TargetBaseAddress) ); dp("DmKdReadPhysicalMemory\n"); EnterCriticalSection(&csPacket); if (TransferCount > PACKET_MAX_SIZE) { // Read the partial the first time. cb = TransferCount % PACKET_MAX_SIZE; } else { cb = TransferCount; } cb2 = 0; if (ARGUMENT_PRESENT(ActualBytesRead)) { *ActualBytesRead = 0; } while (TransferCount != 0) { // Format state manipulate message // 64 bit m64.ApiNumber = DbgKdReadPhysicalMemoryApi; m64.ReturnStatus = STATUS_PENDING; a->TargetBaseAddress = TargetBaseAddress+cb2; a->TransferCount = cb; a->ActualBytesRead = 0L; // 32 bit m32.ApiNumber = DbgKdReadPhysicalMemoryApi; m32.ReturnStatus = STATUS_PENDING; a32->TargetBaseAddress = (ULONG) TargetBaseAddress+cb2; a32->TransferCount = cb; a32->ActualBytesRead = 0L; // Send the message and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply ); } while (rc == FALSE); // If this is not a ReadMemory response then protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdReadPhysicalMemoryApi); // Reset message address to reply. a = &Reply->u.ReadMemory; assert(a->ActualBytesRead <= cb); // Return actual bytes read, and then transfer the bytes if (ARGUMENT_PRESENT(ActualBytesRead)) { *ActualBytesRead += a->ActualBytesRead; } st = Reply->ReturnStatus; // Since read response data follows message, Reply+1 should point // at the data memcpy((PCHAR)((UINT_PTR) UserInterfaceBuffer+cb2), Reply+1, (int)a->ActualBytesRead); if (st != STATUS_SUCCESS) { TransferCount = 0; } else { TransferCount -= cb; cb2 += cb; cb = PACKET_MAX_SIZE; } } LeaveCriticalSection(&csPacket); return st; } DWORD DmKdWritePhysicalMemory( IN ULONG64 TargetBaseAddress, OUT PVOID UserInterfaceBuffer, IN ULONG TransferCount, OUT PULONG ActualBytesWritten OPTIONAL ) /*++ Routine Description: This function writes the specified data to the physical memory of the system being debugged. Arguments: TargetBaseAddress - Supplies the physical address of the memory to write to the system being debugged. UserInterfaceBuffer - Supplies the address of the buffer in the user interface that contains the data to be written. TransferCount - Specifies the number of bytes to write. ActualBytesWritten - An optional parameter that if supplied, returns the number of bytes actually written. Return Value: STATUS_SUCCESS - The specified read occured. STATUS_BUFFER_OVERFLOW - A read that is to large was specified. STATUS_ACCESS_VIOLATION - TBD // Can you even HAVE an access // violation with a physical // memory access?? !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_WRITE_MEMORY64 a = &m64.u.WriteMemory; PDBGKD_WRITE_MEMORY32 a32 = &m32.u.WriteMemory; DWORD st; BOOL rc; ULONG cb, cb2; dp("DmKdWritePhysicalMemory\n"); assert( Is64PtrSE(TargetBaseAddress) ); EnterCriticalSection(&csPacket); if (TransferCount > PACKET_MAX_SIZE) { // Read the partial the first time. cb = TransferCount % PACKET_MAX_SIZE; } else { cb = TransferCount; } cb2 = 0; if (ARGUMENT_PRESENT(ActualBytesWritten)) { *ActualBytesWritten = 0; } while (TransferCount != 0) { // Format state manipulate message // 64 bit m64.ApiNumber = DbgKdWritePhysicalMemoryApi; m64.ReturnStatus = STATUS_PENDING; a->TargetBaseAddress = TargetBaseAddress+cb2; a->TransferCount = cb; a->ActualBytesWritten = 0L; // 32 bit m32.ApiNumber = DbgKdWritePhysicalMemoryApi; m32.ReturnStatus = STATUS_PENDING; a32->TargetBaseAddress = (ULONG) TargetBaseAddress+cb2; a32->TransferCount = cb; a32->ActualBytesWritten = 0L; // Send the message and data to write and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, (PVOID)((UINT_PTR)UserInterfaceBuffer+cb2), (USHORT)cb ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a WriteMemory response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdWritePhysicalMemoryApi); // Reset message address to reply. a = &Reply->u.WriteMemory; assert(a->ActualBytesWritten <= cb); // Return actual bytes written if (ARGUMENT_PRESENT(ActualBytesWritten)) { *ActualBytesWritten += a->ActualBytesWritten; } st = Reply->ReturnStatus; if (st != STATUS_SUCCESS) { TransferCount = 0; } else { TransferCount -= cb; cb2 += cb; cb = PACKET_MAX_SIZE; } } LeaveCriticalSection(&csPacket); return st; } DWORD DmKdReboot( VOID ) /*++ Routine Description: This function reboots being debugged. Arguments: None. Return Value: None. --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdRebootApi; m64.ReturnStatus = STATUS_PENDING; // 32 bit m32.ApiNumber = DbgKdRebootApi; m32.ReturnStatus = STATUS_PENDING; // Send the message. if (!DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 )) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } LeaveCriticalSection(&csPacket); return STATUS_SUCCESS; } DWORD DmKdGetContext( IN USHORT Processor, IN OUT PCONTEXT Context ) /*++ Routine Description: This function reads the context from the system being debugged. The ContextFlags field determines how much context is read. Arguments: Processor - Supplies a processor number to get context from. Context - On input, the ContextFlags field controls what portions of the context record the caller as interested in reading. On output, the context record returns the current context for the processor that reported the last state change. Return Value: STATUS_SUCCESS - The specified get context occured. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_GET_CONTEXT a = &m64.u.GetContext; DWORD st; BOOL rc; dp("DmKdGetContext\n"); // Format state manipulate message EnterCriticalSection(&csPacket); m64.ApiNumber = DbgKdGetContextApi; m64.ReturnStatus = STATUS_PENDING; m64.Processor = Processor; DbgkdManipulateState64To32(&m64, &m32); // Send the message and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a GetContext response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdGetContextApi); // Reset message address to reply. a = &Reply->u.GetContext; st = Reply->ReturnStatus; // Since get context response data follows message, Reply+1 should point // at the data memcpy(Context, Reply+1, sizeof(*Context)); #if defined(TARGET_i386) if (vs.MinorVersion < CONTEXT_SIZE_NT5_VERSION) { ZeroMemory(Context->ExtendedRegisters, sizeof(Context->ExtendedRegisters)); } #endif LeaveCriticalSection(&csPacket); return st; } DWORD DmKdSetContext( IN USHORT Processor, IN CONST CONTEXT *Context ) /*++ Routine Description: This function writes the specified context to the system being debugged. Arguments: Processor - Supplies a processor number to set the context to. Context - Supplies a context record used to set the context for the processor that reported the last state change. Only the portions of the context indicated by the ContextFlags field are actually written. Return Value: STATUS_SUCCESS - The specified set context occured. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_SET_CONTEXT a = &m64.u.SetContext; PDBGKD_SET_CONTEXT a32 = &m32.u.SetContext; DWORD st; BOOL rc; USHORT ContextSize; dp("DmKdSetContext\n"); // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdSetContextApi; m64.ReturnStatus = STATUS_PENDING; m64.Processor = Processor; a->ContextFlags = Context->ContextFlags; // 32 bit m32.ApiNumber = DbgKdSetContextApi; m32.ReturnStatus = STATUS_PENDING; m32.Processor = Processor; a32->ContextFlags = Context->ContextFlags; #if defined(TARGET_i386) if (vs.MinorVersion < CONTEXT_SIZE_NT5_VERSION) { ContextSize = CONTEXT_SIZE_PRE_NT5; } else { ContextSize = sizeof(*Context); } #else ContextSize = sizeof(*Context); #endif // Send the message and context and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, (PVOID)Context, ContextSize ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a SetContext response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdSetContextApi); // Reset message address to reply. a = &Reply->u.SetContext; st = Reply->ReturnStatus; // Check if the current command has been canceled. LeaveCriticalSection(&csPacket); return st; } DWORD DmKdWriteBreakPoint( IN ULONG64 BreakPointAddress, OUT PULONG BreakPointHandle ) /*++ Routine Description: This function is used to write a breakpoint at the address specified. Arguments: BreakPointAddress - Supplies the address that a breakpoint instruction is to be written. This address is interpreted using the current mapping on the processor reporting the previous state change. If the address refers to a page that is not valid, the the breakpoint is remembered by the system. As each page is made valid, the system will check for pending breakpoints and install breakpoints as necessary. BreakPointHandle - Returns a handle to a breakpoint. This handle may be used in a subsequent call to DmKdRestoreBreakPoint. Return Value: STATUS_SUCCESS - The specified breakpoint write occured. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_WRITE_BREAKPOINT64 a = &m64.u.WriteBreakPoint; PDBGKD_WRITE_BREAKPOINT32 a32 = &m32.u.WriteBreakPoint; DWORD st; BOOL rc; assert( Is64PtrSE(BreakPointAddress) ); dp("DmKdWriteBreakPoint\n"); // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdWriteBreakPointApi; m64.ReturnStatus = STATUS_PENDING; a->BreakPointAddress = BreakPointAddress; // 32 bit m32.ApiNumber = DbgKdWriteBreakPointApi; m32.ReturnStatus = STATUS_PENDING; a32->BreakPointAddress = (ULONG) BreakPointAddress; // Send the message and context and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a WriteBreakPoint response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdWriteBreakPointApi); // Reset message address to reply. a = &Reply->u.WriteBreakPoint; st = Reply->ReturnStatus; *BreakPointHandle = a->BreakPointHandle; // Check should we return to caller or to kd prompt. LeaveCriticalSection(&csPacket); return st; } DWORD DmKdRestoreBreakPoint( IN ULONG BreakPointHandle ) /*++ Routine Description: This function is used to restore a breakpoint to its original value. Arguments: BreakPointHandle - Supplies a handle returned by DmKdWriteBreakPoint. This handle must refer to a valid address. The contents of the address must also be a breakpoint instruction. If both of these are true, then the original value at the breakpoint address is restored. Return Value: STATUS_SUCCESS - The specified breakpoint restore occured. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_RESTORE_BREAKPOINT a = &m64.u.RestoreBreakPoint; PDBGKD_RESTORE_BREAKPOINT a32 = &m32.u.RestoreBreakPoint; DWORD st; BOOL rc; dp("DmKdRestoreBreakPoint\n"); // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdRestoreBreakPointApi; m64.ReturnStatus = STATUS_PENDING; a->BreakPointHandle = BreakPointHandle; // 32 bit m32.ApiNumber = DbgKdRestoreBreakPointApi; m32.ReturnStatus = STATUS_PENDING; a32->BreakPointHandle = BreakPointHandle; // Send the message and context and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a RestoreBreakPoint response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdRestoreBreakPointApi); // Reset message address to reply. a = &Reply->u.RestoreBreakPoint; st = Reply->ReturnStatus; // free the packet LeaveCriticalSection(&csPacket); return st; } DWORD DmKdReadIoSpace( IN ULONG64 IoAddress, OUT PVOID ReturnedData, IN ULONG DataSize ) /*++ Routine Description: This function is used read a byte, short, or long (1,2,4 bytes) from the specified I/O address. Arguments: IoAddress - Supplies the Io address to read from. ReturnedData - Supplies the value read from the I/O address. DataSize - Supplies the size in bytes to read. Values of 1, 2, or 4 are accepted. Return Value: STATUS_SUCCESS - Data was successfully read from the I/O address. STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was specified. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_READ_WRITE_IO64 a = &m64.u.ReadWriteIo; PDBGKD_READ_WRITE_IO32 a32 = &m32.u.ReadWriteIo; DWORD st; BOOL rc; dp("DmKdReadIoSpace\n"); assert( Is64PtrSE(IoAddress) ); EnterCriticalSection(&csPacket); switch ( DataSize ) { case 1: case 2: case 4: break; default: LeaveCriticalSection(&csPacket); return (DWORD)STATUS_INVALID_PARAMETER; } // Format state manipulate message // 64 bit m64.ApiNumber = DbgKdReadIoSpaceApi; m64.ReturnStatus = STATUS_PENDING; a->DataSize = DataSize; a->IoAddress = IoAddress; // 32 bit m32.ApiNumber = DbgKdReadIoSpaceApi; m32.ReturnStatus = STATUS_PENDING; a32->DataSize = DataSize; a32->IoAddress = (ULONG) IoAddress; // Send the message and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a ReadIo response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdReadIoSpaceApi); // Reset message address to reply. a = &Reply->u.ReadWriteIo; st = Reply->ReturnStatus; switch ( DataSize ) { case 1: *(PUCHAR)ReturnedData = (UCHAR)a->DataValue; break; case 2: *(PUSHORT)ReturnedData = (USHORT)a->DataValue; break; case 4: *(PULONG)ReturnedData = a->DataValue; break; } // Check if current command has been canceled. If yes, go back to // kd prompt. BUGBUG Do we really need to check for this call? LeaveCriticalSection(&csPacket); return st; } DWORD DmKdWriteIoSpace( IN ULONG64 IoAddress, IN ULONG DataValue, IN ULONG DataSize ) /*++ Routine Description: This function is used write a byte, short, or long (1,2,4 bytes) to the specified I/O address. Arguments: IoAddress - Supplies the Io address to write to. DataValue - Supplies the value to write to the I/O address. DataSize - Supplies the size in bytes to write. Values of 1, 2, or 4 are accepted. Return Value: STATUS_SUCCESS - Data was successfully written to the I/O address. STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was specified. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_READ_WRITE_IO64 a = &m64.u.ReadWriteIo; PDBGKD_READ_WRITE_IO32 a32 = &m32.u.ReadWriteIo; DWORD st; BOOL rc; dp("DmKdWriteIoSpace\n"); assert( Is64PtrSE(IoAddress) ); EnterCriticalSection(&csPacket); switch ( DataSize ) { case 1: case 2: case 4: break; default: LeaveCriticalSection(&csPacket); return (DWORD)STATUS_INVALID_PARAMETER; } // Format state manipulate message // 64 bit m64.ApiNumber = DbgKdWriteIoSpaceApi; m64.ReturnStatus = STATUS_PENDING; a->DataSize = DataSize; a->IoAddress = IoAddress; a->DataValue = DataValue; // 32 bit m32.ApiNumber = DbgKdWriteIoSpaceApi; m32.ReturnStatus = STATUS_PENDING; a32->DataSize = DataSize; a32->IoAddress = (ULONG) IoAddress; a32->DataValue = DataValue; // Send the message and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a WriteIo response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdWriteIoSpaceApi); // Reset message address to reply. a = &Reply->u.ReadWriteIo; st = Reply->ReturnStatus; // free the packet // Check should we return to caller or to kd prompt. LeaveCriticalSection(&csPacket); return st; } DWORD DmKdReadIoSpaceEx( IN ULONG64 IoAddress, OUT PVOID ReturnedData, IN ULONG DataSize, IN ULONG InterfaceType, IN ULONG BusNumber, IN ULONG AddressSpace ) /*++ Routine Description: This function is used read a byte, short, or long (1,2,4 bytes) from the specified I/O address. Arguments: IoAddress - Supplies the Io address to read from. ReturnedData - Supplies the value read from the I/O address. DataSize - Supplies the size in bytes to read. Values of 1, 2, or 4 are accepted. Return Value: STATUS_SUCCESS - Data was successfully read from the I/O address. STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was specified. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_READ_WRITE_IO_EXTENDED64 a = &m64.u.ReadWriteIoExtended; PDBGKD_READ_WRITE_IO_EXTENDED32 a32 = &m32.u.ReadWriteIoExtended; DWORD st; BOOL rc; dp("DmKdReadIoSpaceEx\n"); assert( Is64PtrSE(IoAddress) ); EnterCriticalSection(&csPacket); switch ( DataSize ) { case 1: case 2: case 4: break; default: LeaveCriticalSection(&csPacket); return (DWORD)STATUS_INVALID_PARAMETER; } // Format state manipulate message // 64 bit m64.ApiNumber = DbgKdReadIoSpaceExtendedApi; m64.ReturnStatus = STATUS_PENDING; a->DataSize = DataSize; a->IoAddress = IoAddress; a->InterfaceType = InterfaceType; a->BusNumber = BusNumber; a->AddressSpace = AddressSpace; // 32 bit m32.ApiNumber = DbgKdReadIoSpaceExtendedApi; m32.ReturnStatus = STATUS_PENDING; a32->DataSize = DataSize; a32->IoAddress = (ULONG) IoAddress; a32->InterfaceType = InterfaceType; a32->BusNumber = BusNumber; a32->AddressSpace = AddressSpace; // Send the message and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a ReadIo response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdReadIoSpaceExtendedApi); // Reset message address to reply. a = &Reply->u.ReadWriteIoExtended; st = Reply->ReturnStatus; switch ( DataSize ) { case 1: *(PUCHAR)ReturnedData = (UCHAR)a->DataValue; break; case 2: *(PUSHORT)ReturnedData = (USHORT)a->DataValue; break; case 4: *(PULONG)ReturnedData = a->DataValue; break; } // Check if current command has been canceled. If yes, go back to // kd prompt. BUGBUG Do we really need to check for this call? LeaveCriticalSection(&csPacket); return st; } DWORD DmKdWriteIoSpaceEx( IN ULONG64 IoAddress, IN ULONG DataValue, IN ULONG DataSize, IN ULONG InterfaceType, IN ULONG BusNumber, IN ULONG AddressSpace ) /*++ Routine Description: This function is used write a byte, short, or long (1,2,4 bytes) to the specified I/O address. Arguments: IoAddress - Supplies the Io address to write to. DataValue - Supplies the value to write to the I/O address. DataSize - Supplies the size in bytes to write. Values of 1, 2, or 4 are accepted. Return Value: STATUS_SUCCESS - Data was successfully written to the I/O address. STATUS_INVALID_PARAMETER - A DataSize value other than 1,2, or 4 was specified. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_READ_WRITE_IO_EXTENDED64 a = &m64.u.ReadWriteIoExtended; PDBGKD_READ_WRITE_IO_EXTENDED32 a32 = &m32.u.ReadWriteIoExtended; DWORD st; BOOL rc; dp("DmKdWriteIoSpaceEx\n"); assert( Is64PtrSE(IoAddress) ); EnterCriticalSection(&csPacket); switch ( DataSize ) { case 1: case 2: case 4: break; default: LeaveCriticalSection(&csPacket); return (DWORD)STATUS_INVALID_PARAMETER; } // Format state manipulate message // 64 bit m64.ApiNumber = DbgKdWriteIoSpaceExtendedApi; m64.ReturnStatus = STATUS_PENDING; a->DataSize = DataSize; a->IoAddress = IoAddress; a->DataValue = DataValue; a->InterfaceType = InterfaceType; a->BusNumber = BusNumber; a->AddressSpace = AddressSpace; // 32 bit m32.ApiNumber = DbgKdWriteIoSpaceExtendedApi; m32.ReturnStatus= STATUS_PENDING; a32->DataSize = DataSize; a32->IoAddress = (ULONG) IoAddress; a32->DataValue = DataValue; a32->InterfaceType = InterfaceType; a32->BusNumber = BusNumber; a32->AddressSpace = AddressSpace; // Send the message and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a WriteIo response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdWriteIoSpaceExtendedApi); // Reset message address to reply. a = &Reply->u.ReadWriteIoExtended; st = Reply->ReturnStatus; // free the packet // Check should we return to caller or to kd prompt. LeaveCriticalSection(&csPacket); return st; } DWORD DmKdReadMemoryWrapper( IN ULONG64 TargetBaseAddress, OUT PVOID UserInterfaceBuffer, IN ULONG TransferCount, OUT PULONG ActualBytesRead OPTIONAL ) /*++ Routine Description: Wrapper around DmpReadMemory and DmKdReadVirtualMemory. Arguments: See the documentation for DmpReadMemory and DmKdReadVirtualMemory. Return Value: See the documentation for DmKdReadVirtualMemory. --*/ { extern BOOL fCrashDump; ULONG Result; DWORD Status; if ( !fCrashDump ) { Status = DmKdReadVirtualMemory(TargetBaseAddress, UserInterfaceBuffer, TransferCount, &Result); } else { Result = DmpReadMemory(TargetBaseAddress, UserInterfaceBuffer, TransferCount ); if (Result == TransferCount) { Status = STATUS_SUCCESS; } else { // Return something for an error code Status = STATUS_ACCESS_VIOLATION; } } if ( ActualBytesRead ) { *ActualBytesRead = Result; } return Status; } DWORD DmKdReadVirtualMemory( IN ULONG64 TargetBaseAddress, OUT PVOID UserInterfaceBuffer, IN ULONG TransferCount, OUT PULONG ActualBytesRead OPTIONAL ) /*++ Routine Description: Interface to read VirtualMemory from target machine. Goes through cached memory addresses, then through serial port. Arguments: TargetBaseAddress - Supplies the base address of the memory to read from the system being debugged. The virtual address is in terms of the current mapping for the processor that reported the last state change. Until we figure out how to do this differently, the virtual address must refer to a valid page (although it does not necesserily have to be in the TB). UserInterfaceBuffer - Supplies the address of the buffer in the user interface that data read is to be placed. TransferCount - Specifies the number of bytes to read. ActualBytesRead - An optional parameter that if supplied, returns the number of bytes actually read. Return Value: STATUS_SUCCESS - The specified read occured. STATUS_BUFFER_OVERFLOW - A read that is to large was specified. STATUS_ACCESS_VIOLATION - The TargetBaseAddress/TransferCount parameters refers to invalid virtual memory. !NT_SUCCESS() - TBD --*/ { ULONG BytesRead=0; ULONG BytesRequested=TransferCount; DWORD rc=0; dp("DmKdReadVirtualMemory\n"); assert( Is64PtrSE(TargetBaseAddress) ); EnterCriticalSection(&csPacket); rc = DmKdReadCachedVirtualMemory(TargetBaseAddress, (ULONG) BytesRequested, (PUCHAR) UserInterfaceBuffer, &BytesRead, FALSE ); if (BytesRead > TransferCount) { BytesRead = TransferCount; } if (ActualBytesRead) { *ActualBytesRead = BytesRead; } LeaveCriticalSection(&csPacket); return rc; } DWORD DmKdReadVirtualMemoryNow( IN ULONG64 TargetBaseAddress, OUT PVOID UserInterfaceBuffer, IN ULONG TransferCount, OUT PULONG ActualBytesRead OPTIONAL ) /*++ Routine Description: This function reads the specified data from the system being debugged using the current mapping of the processor. Arguments: TargetBaseAddress - Supplies the base address of the memory to read from the system being debugged. The virtual address is in terms of the current mapping for the processor that reported the last state change. Until we figure out how to do this differently, the virtual address must refer to a valid page (although it does not necesserily have to be in the TB). UserInterfaceBuffer - Supplies the address of the buffer in the user interface that data read is to be placed. TransferCount - Specifies the number of bytes to read. ActualBytesRead - An optional parameter that if supplied, returns the number of bytes actually read. Return Value: STATUS_SUCCESS - The specified read occured. STATUS_BUFFER_OVERFLOW - A read that is to large was specified. STATUS_ACCESS_VIOLATION - The TargetBaseAddress/TransferCount parameters refers to invalid virtual memory. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_READ_MEMORY64 a = &m64.u.ReadMemory; PDBGKD_READ_MEMORY32 a32 = &m32.u.ReadMemory; DWORD st; BOOL rc; DWORD cb, cb2; dp("DmKdReadVirtualMemoryNow\n"); assert( Is64PtrSE(TargetBaseAddress) ); EnterCriticalSection(&csPacket); if (TransferCount > PACKET_MAX_SIZE) { // Read the partial the first time. cb = TransferCount % PACKET_MAX_SIZE; } else { cb = TransferCount; } cb2 = 0; if (ARGUMENT_PRESENT(ActualBytesRead)) { *ActualBytesRead = 0; } while (TransferCount != 0) { // Format state manipulate message // 64 bit m64.ApiNumber = DbgKdReadVirtualMemoryApi; m64.ReturnStatus = STATUS_PENDING; a->TargetBaseAddress = TargetBaseAddress+cb2; a->TransferCount = cb; a->ActualBytesRead = 0L; // 32 bit m32.ApiNumber = DbgKdReadVirtualMemoryApi; m32.ReturnStatus = STATUS_PENDING; a32->TargetBaseAddress = (ULONG) (TargetBaseAddress+cb2); a32->TransferCount = cb; a32->ActualBytesRead = 0L; // Send the message and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply ); } while (rc == FALSE); // If this is not a ReadMemory response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdReadVirtualMemoryApi); // Reset message address to reply. a = &Reply->u.ReadMemory; assert(a->ActualBytesRead <= cb); // Return actual bytes read, and then transfer the bytes if (ARGUMENT_PRESENT(ActualBytesRead)) { *ActualBytesRead += a->ActualBytesRead; } // Since read response data follows message, Reply+1 should point // at the data memcpy((PVOID)((UINT_PTR)UserInterfaceBuffer+cb2), Reply+1, (int)a->ActualBytesRead); st = Reply->ReturnStatus; if (st != STATUS_SUCCESS) { TransferCount = 0; } else { TransferCount -= cb; cb2 += cb; cb = PACKET_MAX_SIZE; } } LeaveCriticalSection(&csPacket); return st; } DWORD DmKdWriteVirtualMemory( IN ULONG64 TargetBaseAddress, OUT PVOID UserInterfaceBuffer, IN ULONG TransferCount, OUT PULONG ActualBytesWritten OPTIONAL ) /*++ Routine Description: This function writes the specified data to the system being debugged using the current mapping of the processor. Arguments: TargetBaseAddress - Supplies the base address of the memory to be written into the system being debugged. The virtual address is in terms of the current mapping for the processor that reported the last state change. Until we figure out how to do this differently, the virtual address must refer to a valid page (although it does not necesserily have to be in the TB). UserInterfaceBuffer - Supplies the address of the buffer in the user interface that contains the data to be written. TransferCount - Specifies the number of bytes to write. ActualBytesWritten - An optional parameter that if supplied, returns the number of bytes actually written. Return Value: STATUS_SUCCESS - The specified read occured. STATUS_BUFFER_OVERFLOW - A read that is to large was specified. STATUS_ACCESS_VIOLATION - The TargetBaseAddress/TransferCount parameters refers to invalid virtual memory. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_WRITE_MEMORY64 a = &m64.u.WriteMemory; PDBGKD_WRITE_MEMORY32 a32 = &m32.u.WriteMemory; DWORD st, cb, cb2; BOOL rc; dp("DmKdWriteVirtualMemory\n"); assert( Is64PtrSE(TargetBaseAddress) ); EnterCriticalSection(&csPacket); DmKdWriteCachedVirtualMemory ( TargetBaseAddress, TransferCount, UserInterfaceBuffer ); if (TransferCount > PACKET_MAX_SIZE) { // Read the partial the first time. cb = TransferCount % PACKET_MAX_SIZE; } else { cb = TransferCount; } cb2 = 0; if (ARGUMENT_PRESENT(ActualBytesWritten)) { *ActualBytesWritten = 0; } while (TransferCount != 0) { // Format state manipulate message // 64 bit m64.ApiNumber = DbgKdWriteVirtualMemoryApi; m64.ReturnStatus = STATUS_PENDING; a->TargetBaseAddress = TargetBaseAddress + cb2; a->TransferCount = cb; a->ActualBytesWritten = 0L; // 32 bit m32.ApiNumber = DbgKdWriteVirtualMemoryApi; m32.ReturnStatus = STATUS_PENDING; a32->TargetBaseAddress = (ULONG) (TargetBaseAddress + cb2); a32->TransferCount = cb; a32->ActualBytesWritten = 0L; // Send the message and data to write and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, (PVOID)((UINT_PTR)UserInterfaceBuffer + cb2), (USHORT)cb ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply ); } while (rc == FALSE); // If this is not a WriteMemory response than protocol is screwed up. // assert that protocol is ok. assert(Reply->ApiNumber == DbgKdWriteVirtualMemoryApi); // Reset message address to reply. a = &Reply->u.WriteMemory; assert(a->ActualBytesWritten <= cb); // Return actual bytes written if (ARGUMENT_PRESENT(ActualBytesWritten)) { *ActualBytesWritten += a->ActualBytesWritten; } st = Reply->ReturnStatus; if (st != STATUS_SUCCESS) { TransferCount = 0; } else { TransferCount -= cb; cb2 += cb; cb = PACKET_MAX_SIZE; } } LeaveCriticalSection(&csPacket); return st; } DWORD DmKdReadControlSpace( IN USHORT Processor, IN ULONG64 TargetBaseAddress, OUT PVOID UserInterfaceBuffer, IN ULONG TransferCount, OUT PULONG ActualBytesRead OPTIONAL ) /*++ Routine Description: This function reads the specified data from the control space of the system being debugged. Control space is processor dependent. TargetBaseAddress is mapped to control space in a processor/implementation defined manner. Arguments: Processor - Supplies the processor whoes control space is desired. TargetBaseAddress - Supplies the base address in control space to read. This address is interpreted in an implementation defined manner. UserInterfaceBuffer - Supplies the address of the buffer in the user interface that data read is to be placed. TransferCount - Specifies the number of bytes to read. ActualBytesRead - An optional parameter that if supplied, returns the number of bytes actually read. Return Value: STATUS_SUCCESS - The specified read occured. STATUS_BUFFER_OVERFLOW - A read that is to large was specified. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_READ_MEMORY64 a = &m64.u.ReadMemory; PDBGKD_READ_MEMORY32 a32 = &m32.u.ReadMemory; DWORD st; BOOL rc; dp("DmKdReadControlSpace\n"); assert( Is64PtrSE(TargetBaseAddress) ); // Use the largest struct to calc the size if ( TransferCount + sizeof(m64) > PACKET_MAX_SIZE ) { return (DWORD)STATUS_BUFFER_OVERFLOW; } // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdReadControlSpaceApi; m64.ReturnStatus = STATUS_PENDING; m64.Processor = Processor; a->TargetBaseAddress = TargetBaseAddress; a->TransferCount = TransferCount; a->ActualBytesRead = 0L; // 32 bit m32.ApiNumber = DbgKdReadControlSpaceApi; m32.ReturnStatus = STATUS_PENDING; m32.Processor = Processor; a32->TargetBaseAddress = (ULONG) TargetBaseAddress; a32->TransferCount = TransferCount; a32->ActualBytesRead = 0L; // Send the message and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a ReadControl response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdReadControlSpaceApi); // Reset message address to reply. a = &Reply->u.ReadMemory; assert(a->ActualBytesRead <= TransferCount); // Return actual bytes read, and then transfer the bytes if (ARGUMENT_PRESENT(ActualBytesRead)) { *ActualBytesRead = a->ActualBytesRead; } st = Reply->ReturnStatus; // Since read response data follows message, Reply+1 should point // at the data memcpy(UserInterfaceBuffer, Reply+1, (int)a->ActualBytesRead); // Check if current command has been canceled. If yes, go back to // kd prompt. BUGBUG Do we really need to check for this call? LeaveCriticalSection(&csPacket); return st; } DWORD DmKdWriteControlSpace( IN USHORT Processor, IN ULONG64 TargetBaseAddress, OUT PVOID UserInterfaceBuffer, IN ULONG TransferCount, OUT PULONG ActualBytesWritten OPTIONAL ) /*++ Routine Description: This function writes the specified data to control space on the system being debugged. Control space is processor dependent. TargetBaseAddress is mapped to control space in a processor/implementation defined manner. Arguments: Processor - Supplies the processor whoes control space is desired. TargetBaseAddress - Supplies the base address in control space to be written. UserInterfaceBuffer - Supplies the address of the buffer in the user interface that contains the data to be written. TransferCount - Specifies the number of bytes to write. ActualBytesWritten - An optional parameter that if supplied, returns the number of bytes actually written. Return Value: STATUS_SUCCESS - The specified read occured. STATUS_BUFFER_OVERFLOW - A read that is to large was specified. !NT_SUCCESS() - TBD --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_WRITE_MEMORY64 a = &m64.u.WriteMemory; PDBGKD_WRITE_MEMORY32 a32 = &m32.u.WriteMemory; DWORD st; BOOL rc; dp("DmKdWriteControlSpace\n"); assert( Is64PtrSE(TargetBaseAddress) ); if ( TransferCount + sizeof(m64) > PACKET_MAX_SIZE ) { return (DWORD)STATUS_BUFFER_OVERFLOW; } // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdWriteControlSpaceApi; m64.ReturnStatus = STATUS_PENDING; m64.Processor = Processor; a->TargetBaseAddress = TargetBaseAddress; a->TransferCount = TransferCount; a->ActualBytesWritten = 0L; // 32 bit m32.ApiNumber = DbgKdWriteControlSpaceApi; m32.ReturnStatus = STATUS_PENDING; m32.Processor = Processor; a32->TargetBaseAddress = (ULONG) TargetBaseAddress; a32->TransferCount = TransferCount; a32->ActualBytesWritten = 0L; // Send the message and data to write and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, UserInterfaceBuffer, (USHORT)TransferCount ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a WriteControl response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdWriteControlSpaceApi); // Reset message address to reply. a = &Reply->u.WriteMemory; assert(a->ActualBytesWritten <= TransferCount); // Return actual bytes written *ActualBytesWritten = a->ActualBytesWritten; st = Reply->ReturnStatus; LeaveCriticalSection(&csPacket); return st; } DWORD DmKdContinue ( IN DWORD ContinueStatus ) /*++ Routine Description: Continuing a system that previously reported a state change causes the system to continue executiontion using the context in effect at the time the state change was reported (of course this context could have been modified using the DmKd state manipulation APIs). Arguments: ContinueStatus - Supplies the continuation status to the thread being continued. Valid values for this are DBG_EXCEPTION_HANDLED, DBG_EXCEPTION_NOT_HANDLED or DBG_CONTINUE. Return Value: STATUS_SUCCESS - Successful call to DbgUiContinue STATUS_INVALID_PARAMETER - An invalid continue status or was specified. --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_CONTINUE a = &m64.u.Continue; PDBGKD_CONTINUE a32 = &m32.u.Continue; DWORD st; dp("DmKdContinue\n"); EnterCriticalSection(&csPacket); if ( ContinueStatus == DBG_EXCEPTION_HANDLED || ContinueStatus == DBG_EXCEPTION_NOT_HANDLED || ContinueStatus == DBG_CONTINUE ) { // 64 bit m64.ApiNumber = DbgKdContinueApi; m64.ReturnStatus = ContinueStatus; a->ContinueStatus = ContinueStatus; // 32 bit m32.ApiNumber = DbgKdContinueApi; m32.ReturnStatus = ContinueStatus; a32->ContinueStatus = ContinueStatus; if (!DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 )) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } st = STATUS_SUCCESS; DmKdPurgeCachedVirtualMemory( FALSE ); } else { st = (DWORD)STATUS_INVALID_PARAMETER; } LeaveCriticalSection(&csPacket); return st; } DWORD DmKdContinue2 ( IN DWORD ContinueStatus, IN PDBGKD_CONTROL_SET ControlSet ) /*++ Routine Description: Continuing a system that previously reported a state change causes the system to continue executiontion using the context in effect at the time the state change was reported, modified by the values set in the ControlSet structure. (And, of course, the context could have been modified by used the DmKd state manipulation APIs.) Arguments: ContinueStatus - Supplies the continuation status to the thread being continued. Valid values for this are DBG_EXCEPTION_HANDLED, DBG_EXCEPTION_NOT_HANDLED or DBG_CONTINUE. ControlSet - Supplies a pointer to a structure containing the machine specific control data to set. For the x86 this is the TraceFlag and Dr7. Return Value: STATUS_SUCCESS - Successful call to DbgUiContinue STATUS_INVALID_PARAMETER - An invalid continue status or was specified. --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; DWORD st; dp("DmKdContinue2\n"); EnterCriticalSection(&csPacket); if ( ContinueStatus == DBG_EXCEPTION_HANDLED || ContinueStatus == DBG_EXCEPTION_NOT_HANDLED || ContinueStatus == DBG_CONTINUE ) { // 64 bit m64.ApiNumber = DbgKdContinueApi2; m64.ReturnStatus = ContinueStatus; m64.u.Continue2.ContinueStatus = ContinueStatus; m64.u.Continue2.ControlSet = *ControlSet; // 32 bit m32.ApiNumber = DbgKdContinueApi2; m32.ReturnStatus = ContinueStatus; m32.u.Continue2.ContinueStatus = ContinueStatus; m32.u.Continue2.ControlSet = *ControlSet; if (!DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 )) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } st = STATUS_SUCCESS; DmKdPurgeCachedVirtualMemory( FALSE ); } else { st = (DWORD)STATUS_INVALID_PARAMETER; } LeaveCriticalSection(&csPacket); return st; } DWORD DmKdSetSpecialCalls ( IN ULONG NumSpecialCalls, IN PULONG64 Calls ) /*++ Routine Description: Inform the debugged kernel that calls to these addresses are "special" calls, and they should result in callbacks to the kernel debugger rather than continued local stepping. The new values *replace* any old ones that may have previously set (not that you're likely to want to change this). Arguments: NumSpecialCalls - how many special calls there are Calls - pointer to an array of calls. Return Value: STATUS_SUCCESS - Successful call to DbgUiContinue STATUS_INVALID_PARAMETER - The number of special calls wasn't between 0 and MAX_SPECIAL_CALLS. --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; ULONG i; dp("DmKdSetSpecialCalls\n"); EnterCriticalSection(&csPacket); #if 0 ClearTraceDataSyms(); #endif // 64 bit m64.ApiNumber = DbgKdClearSpecialCallsApi; m64.ReturnStatus = STATUS_PENDING; // 32 bit m32.ApiNumber = DbgKdClearSpecialCallsApi; m32.ReturnStatus = STATUS_PENDING; if (!DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 )) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } DmKdPurgeCachedVirtualMemory( FALSE ); for (i = 0; i < NumSpecialCalls; i++) { // 64 bit m64.ApiNumber = DbgKdSetSpecialCallApi; m64.ReturnStatus = STATUS_PENDING; m64.u.SetSpecialCall.SpecialCall = Calls[i]; // 32 bit m32.ApiNumber = DbgKdSetSpecialCallApi; m32.ReturnStatus = STATUS_PENDING; m32.u.SetSpecialCall.SpecialCall = (ULONG) Calls[i]; if (!DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 )) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } } LeaveCriticalSection(&csPacket); return STATUS_SUCCESS; } DWORD DmKdSetInternalBp ( ULONG64 addr, ULONG flags ) /*++ Routine Description: Inform the debugged kernel that a breakpoint at this address is to be internally counted, and not result in a callback to the remote debugger (us). This function DOES NOT cause the kernel to set the breakpoint; the debugger must do that independently. Arguments: Addr - address of the breakpoint Flags - the breakpoint flags to set (note: if the invalid bit is set, this CLEARS a breakpoint). Return Value: STATUS_SUCCESS - Successful call to DbgUiContinue --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; DWORD st; dp("DmKdSetInternalBp\n"); assert( Is64PtrSE(addr) ); EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdSetInternalBreakPointApi; m64.ReturnStatus = STATUS_PENDING; m64.u.SetInternalBreakpoint.BreakpointAddress = addr; m64.u.SetInternalBreakpoint.Flags = flags; // 64 bit m32.ApiNumber = DbgKdSetInternalBreakPointApi; m32.ReturnStatus = STATUS_PENDING; m32.u.SetInternalBreakpoint.BreakpointAddress = (ULONG) addr; m32.u.SetInternalBreakpoint.Flags = flags; if (!DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 )) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } st = STATUS_SUCCESS; LeaveCriticalSection(&csPacket); return st; } DWORD DmKdGetInternalBp ( ULONG64 addr, PULONG flags, PULONG calls, PULONG minInstr, PULONG maxInstr, PULONG totInstr, PULONG maxCPS ) /*++ Routine Description: Query the status of an internal breakpoint from the debugged kernel and return the data to the caller. Arguments: Addr - address of the breakpoint flags, calls, minInstr, maxInstr, totInstr - values returned describing the particular breakpoint. flags will contain the invalid bit if the breakpoint is bogus. Return Value: STATUS_SUCCESS - Successful call to DbgUiContinue --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; DWORD st; ULONG rc; dp("DmKdGetInternalBp\n"); assert( Is64PtrSE(addr) ); EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdGetInternalBreakPointApi; m64.ReturnStatus = STATUS_PENDING; m64.u.GetInternalBreakpoint.BreakpointAddress = addr; // 32 bit m32.ApiNumber = DbgKdGetInternalBreakPointApi; m32.ReturnStatus = STATUS_PENDING; m32.u.GetInternalBreakpoint.BreakpointAddress = (ULONG) addr; do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE, &Reply ); } while (rc == FALSE); *flags = Reply->u.GetInternalBreakpoint.Flags; *calls = Reply->u.GetInternalBreakpoint.Calls; *maxCPS = Reply->u.GetInternalBreakpoint.MaxCallsPerPeriod; *maxInstr = Reply->u.GetInternalBreakpoint.MaxInstructions; *minInstr = Reply->u.GetInternalBreakpoint.MinInstructions; *totInstr = Reply->u.GetInternalBreakpoint.TotalInstructions; st = STATUS_SUCCESS; LeaveCriticalSection(&csPacket); return st; } DWORD DmKdGetVersion ( PDBGKD_GET_VERSION64 GetVersion ) { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_GET_VERSION64 a = &m64.u.GetVersion64; PDBGKD_GET_VERSION32 a32 = &m32.u.GetVersion32; DWORD st; ULONG rc; extern BOOL KdCacheDecodePTEs; dp("DmKdGetVersion\n"); // 64 bit m64.ApiNumber = DbgKdGetVersionApi; m64.ReturnStatus = STATUS_PENDING; a->ProtocolVersion = 1; // request context records on state changes // 32 bit m32.ApiNumber = DbgKdGetVersionApi; m32.ReturnStatus = STATUS_PENDING; a32->ProtocolVersion = 1; // request context records on state changes do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket( PACKET_TYPE_KD_STATE_MANIPULATE, &Reply ); } while (rc == FALSE); *GetVersion = Reply->u.GetVersion64; DmKdPtr64 = ((GetVersion->Flags & DBGKD_VERS_FLAG_PTR64) == DBGKD_VERS_FLAG_PTR64); if (GetVersion->Flags & DBGKD_VERS_FLAG_NOMM) { KdCacheDecodePTEs = FALSE; } st = Reply->ReturnStatus; #if defined(TARGET_i386) if (vs.MinorVersion < CONTEXT_SIZE_NT5_VERSION) { ContextSize = CONTEXT_SIZE_PRE_NT5; } else { ContextSize = sizeof(CONTEXT); } #else ContextSize = sizeof(CONTEXT); #endif return st; } DWORD DmKdCrash( DWORD BugCheckCode ) { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; dp("DmKdCrash\n"); // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdCauseBugCheckApi; m64.ReturnStatus = STATUS_PENDING; *(PULONG)&m64.u = BugCheckCode; // 32 bit m32.ApiNumber = DbgKdCauseBugCheckApi; m32.ReturnStatus = STATUS_PENDING; *(PULONG)&m32.u = BugCheckCode; // Send the message. DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); LeaveCriticalSection(&csPacket); return STATUS_SUCCESS; } DWORD DmKdWriteBreakPointEx( IN ULONG BreakPointCount, IN OUT PDBGKD_WRITE_BREAKPOINT64 BreakPoints, IN DWORD ContinueStatus ) { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; PDBGKD_MANIPULATE_STATE64 Reply; PDBGKD_BREAKPOINTEX a = &m64.u.BreakPointEx; PDBGKD_BREAKPOINTEX a32 = &m32.u.BreakPointEx; DWORD st; BOOL rc; dp("DmKdWriteBreakPointEx\n"); // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdWriteBreakPointExApi; m64.ReturnStatus = STATUS_PENDING; a->BreakPointCount = BreakPointCount; a->ContinueStatus = (NTSTATUS)ContinueStatus; // 32 bit m32.ApiNumber = DbgKdWriteBreakPointExApi; m32.ReturnStatus = STATUS_PENDING; a32->BreakPointCount = BreakPointCount; a32->ContinueStatus = (NTSTATUS)ContinueStatus; // Send the message and context and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, (PVOID)BreakPoints, (USHORT)(sizeof(*BreakPoints) * BreakPointCount) ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply); } while (rc == FALSE); // If this is not a SetContext response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdWriteBreakPointExApi); // Reset message address to reply. a = &Reply->u.BreakPointEx; st = Reply->ReturnStatus; memcpy(BreakPoints, Reply+1, sizeof(*BreakPoints) * BreakPointCount ); BreakPointCount = a->BreakPointCount; // Check if the current command has been canceled. LeaveCriticalSection(&csPacket); return st; } DWORD DmKdRestoreBreakPointEx( IN ULONG BreakPointCount, IN PDBGKD_RESTORE_BREAKPOINT BreakPointHandles ) { DBGKD_MANIPULATE_STATE64 m64 = {0}; DBGKD_MANIPULATE_STATE32 m32 = {0}; PDBGKD_MANIPULATE_STATE64 Reply; DWORD st; BOOL rc; dp("DmKdRestoreBreakPointEx\n"); // Format state manipulate message EnterCriticalSection(&csPacket); // 64 bit m64.ApiNumber = DbgKdRestoreBreakPointExApi; m64.ReturnStatus = STATUS_PENDING; m64.u.BreakPointEx.BreakPointCount = BreakPointCount; // 32 bit m32.ApiNumber = DbgKdRestoreBreakPointExApi; m32.ReturnStatus = STATUS_PENDING; m32.u.BreakPointEx.BreakPointCount = BreakPointCount; // Send the message and context and then wait for reply do { rc = DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, (PVOID)BreakPointHandles, (USHORT)(sizeof(*BreakPointHandles) * BreakPointCount) ); if (!rc) { LeaveCriticalSection(&csPacket); return (DWORD)STATUS_DATA_ERROR; } rc = DmKdWaitForPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Reply ); } while (rc == FALSE); // If this is not a SetContext response than protocol is screwed up. // assert that protocol is ok. st = Reply->ReturnStatus; assert(Reply->ApiNumber == DbgKdRestoreBreakPointExApi); // Reset message address to reply. st = Reply->ReturnStatus; memcpy(BreakPointHandles, Reply+1, sizeof(*BreakPointHandles) * BreakPointCount ); // Check if the current command has been canceled. LeaveCriticalSection(&csPacket); return st; } NTSTATUS DmKdSwitchActiveProcessor ( IN ULONG ProcessorNumber ) /*++ Routine Description: Arguments: ProcessorNumber - Return Value: STATUS_SUCCESS - Successful call to DbgUiContinue STATUS_INVALID_PARAMETER - An invalid continue status or was specified. --*/ { DBGKD_MANIPULATE_STATE64 m64; DBGKD_MANIPULATE_STATE32 m32; extern BOOL fCrashDump; if (fCrashDump) { DMPrintShellMsg( "DMKD: Cannot change active processors on a crash dump" ); return STATUS_UNSUCCESSFUL; } // 64 bit m64.ApiNumber = (USHORT)DbgKdSwitchProcessor; m64.Processor = (USHORT)ProcessorNumber; // 32 bit m32.ApiNumber = (USHORT)DbgKdSwitchProcessor; m32.Processor = (USHORT)ProcessorNumber; DmKdWritePacket( DmKdApi64 ? (PVOID) &m64 : (PVOID) &m32, DmKdApi64 ? sizeof(m64) : sizeof(m32), PACKET_TYPE_KD_STATE_MANIPULATE, NULL, 0 ); DmKdPurgeCachedVirtualMemory (TRUE); return STATUS_SUCCESS; }