Author: jgardou Date: Sun Sep 14 22:50:10 2014 New Revision: 64156
URL: http://svn.reactos.org/svn/reactos?rev=64156&view=rev Log: [KDGDB] - Fix an embarassing works-for-me but uncommited cast. - Add support for reading registers and memory from foreign threads. Highly experimental and nearly untested, use at your own risk.
Modified: trunk/reactos/drivers/base/kdgdb/gdb_input.c trunk/reactos/drivers/base/kdgdb/i386_sup.c trunk/reactos/drivers/base/kdgdb/kdgdb.h trunk/reactos/drivers/base/kdgdb/kdpacket.c
Modified: trunk/reactos/drivers/base/kdgdb/gdb_input.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/gdb_inpu... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/gdb_input.c [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/gdb_input.c [iso-8859-1] Sun Sep 14 22:50:10 2014 @@ -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 @@ 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 @@ 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; /* ? */ @@ -332,6 +342,19 @@ if (MessageData) 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 @@ 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':
Modified: trunk/reactos/drivers/base/kdgdb/i386_sup.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/i386_sup... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/i386_sup.c [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/i386_sup.c [iso-8859-1] Sun Sep 14 22:50:10 2014 @@ -6,6 +6,8 @@ */
#include "kdgdb.h" + +#include <pstypes.h>
enum reg_name { @@ -79,6 +81,44 @@ 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 @@ _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext) { - ULONG32 Registers[16]; + CHAR Registers[16*8 + 1]; + UCHAR* RegisterPtr; unsigned i; unsigned short size; - - for(i=0; i < 16; i++) - { - Registers[i] = *(ULONG32*)ctx_to_reg(&CurrentContext, i, &size); - } - send_gdb_memory(Registers, sizeof(Registers)); + CHAR* ptr = Registers; + + if (gdb_dbg_thread == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)) + { + 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]; + } + } + 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 @@ /* 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 @@ { send_gdb_memory(ptr, size); } + return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); }
Modified: trunk/reactos/drivers/base/kdgdb/kdgdb.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/kdgdb.h?... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/kdgdb.h [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/kdgdb.h [iso-8859-1] Sun Sep 14 22:50:10 2014 @@ -67,6 +67,7 @@ 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);
Modified: trunk/reactos/drivers/base/kdgdb/kdpacket.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/base/kdgdb/kdpacket... ============================================================================== --- trunk/reactos/drivers/base/kdgdb/kdpacket.c [iso-8859-1] (original) +++ trunk/reactos/drivers/base/kdgdb/kdpacket.c [iso-8859-1] Sun Sep 14 22:50:10 2014 @@ -14,6 +14,7 @@ _In_ ULONG PacketType, _In_ PSTRING MessageHeader, _In_ PSTRING MessageData); +static BOOLEAN CanSendData = FALSE;
/* GLOBALS ********************************************************************/ DBGKD_GET_VERSION64 KdVersion; @@ -141,11 +142,13 @@ /* 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 @@ _In_ DBGKD_DEBUG_IO* DebugIO, _In_ PSTRING String) { + if (!CanSendData) + return; + switch (DebugIO->ApiNumber) { case DbgKdPrintStringApi: