diff --git a/reactos/drivers/base/kdgdb/gdb_input.c b/reactos/drivers/base/kdgdb/gdb_input.c index f58e66bc200..b858a381e0d 100644 --- a/reactos/drivers/base/kdgdb/gdb_input.c +++ b/reactos/drivers/base/kdgdb/gdb_input.c @@ -11,6 +11,8 @@ /* LOCALS *********************************************************************/ static HANDLE gdb_run_thread; +/* We might have to attach to a process to read its memory */ +static PEPROCESS AttachedProcess = NULL; /* Keep track of where we are for qfThreadInfo/qsThreadInfo */ static LIST_ENTRY* CurrentProcessEntry; static LIST_ENTRY* CurrentThreadEntry; @@ -316,6 +318,13 @@ ReadMemorySendHandler( send_gdb_memory(MessageData->Buffer, MessageData->Length); KdpSendPacketHandler = NULL; KdpManipulateStateHandler = NULL; + + /* Detach if we have to */ + if (AttachedProcess != NULL) + { + KeDetachProcess(); + AttachedProcess = NULL; + } } static @@ -323,7 +332,8 @@ KDSTATUS handle_gdb_read_mem( _Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, - _Out_ PULONG MessageLength) + _Out_ PULONG MessageLength, + _Inout_ PKD_CONTEXT KdContext) { State->ApiNumber = DbgKdReadVirtualMemoryApi; State->ReturnStatus = STATUS_SUCCESS; /* ? */ @@ -333,6 +343,19 @@ handle_gdb_read_mem( MessageData->Length = 0; *MessageLength = 0; + /* Attach to the debug process to read its memory */ + if (gdb_dbg_process != PsGetCurrentProcessId()) + { + NTSTATUS Status = PsLookupProcessByProcessId(gdb_dbg_process, &AttachedProcess); + if (!NT_SUCCESS(Status)) + { + KDDBGPRINT("The current GDB debug thread is invalid!"); + send_gdb_packet("E03"); + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); + } + KeAttachProcess(&AttachedProcess->Pcb); + } + State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]); State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1); @@ -416,7 +439,7 @@ gdb_interpret_input( handle_gdb_set_thread(); break; case 'm': - return handle_gdb_read_mem(State, MessageData, MessageLength); + return handle_gdb_read_mem(State, MessageData, MessageLength, KdContext); case 'p': return gdb_send_register(State, MessageData, MessageLength, KdContext); case 'q': diff --git a/reactos/drivers/base/kdgdb/i386_sup.c b/reactos/drivers/base/kdgdb/i386_sup.c index 16cceb1ea19..dc752b531d8 100644 --- a/reactos/drivers/base/kdgdb/i386_sup.c +++ b/reactos/drivers/base/kdgdb/i386_sup.c @@ -7,6 +7,8 @@ #include "kdgdb.h" +#include + enum reg_name { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, @@ -79,6 +81,44 @@ ctx_to_reg(CONTEXT* ctx, enum reg_name name, unsigned short* size) return 0; } +static +void* +thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size) +{ + PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame; + + /* See if the thread was actually scheduled */ + if (TrapFrame == NULL) + { + return NULL; + } + + *size = 4; + switch (reg_name) + { + case EAX: return &TrapFrame->Eax; + case ECX: return &TrapFrame->Ecx; + case EDX: return &TrapFrame->Edx; + case EBX: return &TrapFrame->Ebx; + case ESP: return (TrapFrame->PreviousPreviousMode == KernelMode) ? + &TrapFrame->TempEsp : &TrapFrame->HardwareEsp; + case EBP: return &TrapFrame->Ebp; + case ESI: return &TrapFrame->Esi; + case EDI: return &TrapFrame->Edi; + case EIP: return &TrapFrame->Eip; + case EFLAGS: return &TrapFrame->EFlags; + case CS: return &TrapFrame->SegCs; + case SS: return &TrapFrame->HardwareSegSs; + case DS: return &TrapFrame->SegDs; + case ES: return &TrapFrame->SegEs; + case FS: return &TrapFrame->SegFs; + case GS: return &TrapFrame->SegGs; + default: + KDDBGPRINT("Unhandled regname: %d.\n", reg_name); + } + return NULL; +} + KDSTATUS gdb_send_registers( _Out_ DBGKD_MANIPULATE_STATE64* State, @@ -86,15 +126,62 @@ gdb_send_registers( _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext) { - ULONG32 Registers[16]; + CHAR Registers[16*8 + 1]; + UCHAR* RegisterPtr; unsigned i; unsigned short size; + CHAR* ptr = Registers; - for(i=0; i < 16; i++) + if (gdb_dbg_thread == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)) { - Registers[i] = *(ULONG32*)ctx_to_reg(&CurrentContext, i, &size); + for(i=0; i < 16; i++) + { + RegisterPtr = ctx_to_reg(&CurrentContext, i, &size); + *ptr++ = hex_chars[RegisterPtr[0] >> 4]; + *ptr++ = hex_chars[RegisterPtr[0] & 0xF]; + *ptr++ = hex_chars[RegisterPtr[1] >> 4]; + *ptr++ = hex_chars[RegisterPtr[1] & 0xF]; + *ptr++ = hex_chars[RegisterPtr[2] >> 4]; + *ptr++ = hex_chars[RegisterPtr[2] & 0xF]; + *ptr++ = hex_chars[RegisterPtr[3] >> 4]; + *ptr++ = hex_chars[RegisterPtr[3] & 0xF]; + } } - send_gdb_memory(Registers, sizeof(Registers)); + else + { + PETHREAD DbgThread; + NTSTATUS Status; + + Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread); + if (!NT_SUCCESS(Status)) + { + /* Thread is dead */ + send_gdb_packet("E03"); + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); + } + + for(i=0; i < 16; i++) + { + RegisterPtr = thread_to_reg(DbgThread, i, &size); + if (RegisterPtr) + { + *ptr++ = hex_chars[RegisterPtr[0] >> 4]; + *ptr++ = hex_chars[RegisterPtr[0] & 0xF]; + *ptr++ = hex_chars[RegisterPtr[1] >> 4]; + *ptr++ = hex_chars[RegisterPtr[1] & 0xF]; + *ptr++ = hex_chars[RegisterPtr[2] >> 4]; + *ptr++ = hex_chars[RegisterPtr[2] & 0xF]; + *ptr++ = hex_chars[RegisterPtr[3] >> 4]; + *ptr++ = hex_chars[RegisterPtr[3] & 0xF]; + } + else + { + ptr += sprintf(ptr, "xxxxxxxx"); + } + } + } + *ptr = '\0'; + send_gdb_packet(Registers); return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); } @@ -112,7 +199,27 @@ gdb_send_register( /* Get the GDB register name (gdb_input = "pXX") */ reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]); - ptr = ctx_to_reg(&CurrentContext, reg_name, &size); + if (gdb_dbg_thread == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)) + { + /* We can get it from the context of the current exception */ + ptr = ctx_to_reg(&CurrentContext, reg_name, &size); + } + else + { + PETHREAD DbgThread; + NTSTATUS Status; + + Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread); + if (!NT_SUCCESS(Status)) + { + /* Thread is dead */ + send_gdb_packet("E03"); + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); + } + + ptr = thread_to_reg(DbgThread, reg_name, &size); + } + if (!ptr) { /* Undefined. Let's assume 32 bit register */ @@ -122,5 +229,6 @@ gdb_send_register( { send_gdb_memory(ptr, size); } + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); } diff --git a/reactos/drivers/base/kdgdb/kdgdb.h b/reactos/drivers/base/kdgdb/kdgdb.h index bc18e5b508c..71f788dcebd 100644 --- a/reactos/drivers/base/kdgdb/kdgdb.h +++ b/reactos/drivers/base/kdgdb/kdgdb.h @@ -67,6 +67,7 @@ void send_gdb_memory(_In_ VOID* Buffer, size_t Length); void gdb_send_debug_io(_In_ PSTRING String); void gdb_send_exception(void); void send_gdb_ntstatus(_In_ NTSTATUS Status); +extern const char hex_chars[]; /* kdcom.c */ KDSTATUS NTAPI KdpPollBreakIn(VOID); diff --git a/reactos/drivers/base/kdgdb/kdpacket.c b/reactos/drivers/base/kdgdb/kdpacket.c index 7f86b372a94..238c4db23fc 100644 --- a/reactos/drivers/base/kdgdb/kdpacket.c +++ b/reactos/drivers/base/kdgdb/kdpacket.c @@ -14,6 +14,7 @@ FirstSendHandler( _In_ ULONG PacketType, _In_ PSTRING MessageHeader, _In_ PSTRING MessageData); +static BOOLEAN CanSendData = FALSE; /* GLOBALS ********************************************************************/ DBGKD_GET_VERSION64 KdVersion; @@ -141,11 +142,13 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange) /* Save current state for later GDB queries */ CurrentStateChange = *StateChange; /* Unless GDB tells us otherwise, those are what we should have */ - gdb_dbg_thread = PsGetThreadId((PETHREAD)StateChange->Thread); - gdb_dbg_process = PsGetThreadProcessId((PETHREAD)StateChange->Thread); + gdb_dbg_thread = PsGetThreadId((PETHREAD)(ULONG_PTR)StateChange->Thread); + gdb_dbg_process = PsGetThreadProcessId((PETHREAD)(ULONG_PTR)StateChange->Thread); gdb_send_exception(); /* Next receive call will ask for the context */ KdpManipulateStateHandler = GetContextManipulateHandler; + /* We can now send data, since after this we will be connected to GDB */ + CanSendData = TRUE; break; default: /* FIXME */ @@ -159,6 +162,9 @@ send_kd_debug_io( _In_ DBGKD_DEBUG_IO* DebugIO, _In_ PSTRING String) { + if (!CanSendData) + return; + switch (DebugIO->ApiNumber) { case DbgKdPrintStringApi: