mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 17:34:57 +00:00
[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. svn path=/trunk/; revision=64156
This commit is contained in:
parent
d4fd3a072f
commit
6087abc76f
4 changed files with 147 additions and 9 deletions
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
/* LOCALS *********************************************************************/
|
/* LOCALS *********************************************************************/
|
||||||
static HANDLE gdb_run_thread;
|
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 */
|
/* Keep track of where we are for qfThreadInfo/qsThreadInfo */
|
||||||
static LIST_ENTRY* CurrentProcessEntry;
|
static LIST_ENTRY* CurrentProcessEntry;
|
||||||
static LIST_ENTRY* CurrentThreadEntry;
|
static LIST_ENTRY* CurrentThreadEntry;
|
||||||
|
@ -316,6 +318,13 @@ ReadMemorySendHandler(
|
||||||
send_gdb_memory(MessageData->Buffer, MessageData->Length);
|
send_gdb_memory(MessageData->Buffer, MessageData->Length);
|
||||||
KdpSendPacketHandler = NULL;
|
KdpSendPacketHandler = NULL;
|
||||||
KdpManipulateStateHandler = NULL;
|
KdpManipulateStateHandler = NULL;
|
||||||
|
|
||||||
|
/* Detach if we have to */
|
||||||
|
if (AttachedProcess != NULL)
|
||||||
|
{
|
||||||
|
KeDetachProcess();
|
||||||
|
AttachedProcess = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -323,7 +332,8 @@ KDSTATUS
|
||||||
handle_gdb_read_mem(
|
handle_gdb_read_mem(
|
||||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||||
_Out_ PSTRING MessageData,
|
_Out_ PSTRING MessageData,
|
||||||
_Out_ PULONG MessageLength)
|
_Out_ PULONG MessageLength,
|
||||||
|
_Inout_ PKD_CONTEXT KdContext)
|
||||||
{
|
{
|
||||||
State->ApiNumber = DbgKdReadVirtualMemoryApi;
|
State->ApiNumber = DbgKdReadVirtualMemoryApi;
|
||||||
State->ReturnStatus = STATUS_SUCCESS; /* ? */
|
State->ReturnStatus = STATUS_SUCCESS; /* ? */
|
||||||
|
@ -333,6 +343,19 @@ handle_gdb_read_mem(
|
||||||
MessageData->Length = 0;
|
MessageData->Length = 0;
|
||||||
*MessageLength = 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.TargetBaseAddress = hex_to_address(&gdb_input[1]);
|
||||||
State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
|
State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
|
||||||
|
|
||||||
|
@ -416,7 +439,7 @@ gdb_interpret_input(
|
||||||
handle_gdb_set_thread();
|
handle_gdb_set_thread();
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
return handle_gdb_read_mem(State, MessageData, MessageLength);
|
return handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
|
||||||
case 'p':
|
case 'p':
|
||||||
return gdb_send_register(State, MessageData, MessageLength, KdContext);
|
return gdb_send_register(State, MessageData, MessageLength, KdContext);
|
||||||
case 'q':
|
case 'q':
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include "kdgdb.h"
|
#include "kdgdb.h"
|
||||||
|
|
||||||
|
#include <pstypes.h>
|
||||||
|
|
||||||
enum reg_name
|
enum reg_name
|
||||||
{
|
{
|
||||||
EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
|
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;
|
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
|
KDSTATUS
|
||||||
gdb_send_registers(
|
gdb_send_registers(
|
||||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||||
|
@ -86,15 +126,62 @@ gdb_send_registers(
|
||||||
_Out_ PULONG MessageLength,
|
_Out_ PULONG MessageLength,
|
||||||
_Inout_ PKD_CONTEXT KdContext)
|
_Inout_ PKD_CONTEXT KdContext)
|
||||||
{
|
{
|
||||||
ULONG32 Registers[16];
|
CHAR Registers[16*8 + 1];
|
||||||
|
UCHAR* RegisterPtr;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned short size;
|
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);
|
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") */
|
/* Get the GDB register name (gdb_input = "pXX") */
|
||||||
reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]);
|
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)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
/* Undefined. Let's assume 32 bit register */
|
/* Undefined. Let's assume 32 bit register */
|
||||||
|
@ -122,5 +229,6 @@ gdb_send_register(
|
||||||
{
|
{
|
||||||
send_gdb_memory(ptr, size);
|
send_gdb_memory(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_debug_io(_In_ PSTRING String);
|
||||||
void gdb_send_exception(void);
|
void gdb_send_exception(void);
|
||||||
void send_gdb_ntstatus(_In_ NTSTATUS Status);
|
void send_gdb_ntstatus(_In_ NTSTATUS Status);
|
||||||
|
extern const char hex_chars[];
|
||||||
|
|
||||||
/* kdcom.c */
|
/* kdcom.c */
|
||||||
KDSTATUS NTAPI KdpPollBreakIn(VOID);
|
KDSTATUS NTAPI KdpPollBreakIn(VOID);
|
||||||
|
|
|
@ -14,6 +14,7 @@ FirstSendHandler(
|
||||||
_In_ ULONG PacketType,
|
_In_ ULONG PacketType,
|
||||||
_In_ PSTRING MessageHeader,
|
_In_ PSTRING MessageHeader,
|
||||||
_In_ PSTRING MessageData);
|
_In_ PSTRING MessageData);
|
||||||
|
static BOOLEAN CanSendData = FALSE;
|
||||||
|
|
||||||
/* GLOBALS ********************************************************************/
|
/* GLOBALS ********************************************************************/
|
||||||
DBGKD_GET_VERSION64 KdVersion;
|
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 */
|
/* Save current state for later GDB queries */
|
||||||
CurrentStateChange = *StateChange;
|
CurrentStateChange = *StateChange;
|
||||||
/* Unless GDB tells us otherwise, those are what we should have */
|
/* Unless GDB tells us otherwise, those are what we should have */
|
||||||
gdb_dbg_thread = PsGetThreadId((PETHREAD)StateChange->Thread);
|
gdb_dbg_thread = PsGetThreadId((PETHREAD)(ULONG_PTR)StateChange->Thread);
|
||||||
gdb_dbg_process = PsGetThreadProcessId((PETHREAD)StateChange->Thread);
|
gdb_dbg_process = PsGetThreadProcessId((PETHREAD)(ULONG_PTR)StateChange->Thread);
|
||||||
gdb_send_exception();
|
gdb_send_exception();
|
||||||
/* Next receive call will ask for the context */
|
/* Next receive call will ask for the context */
|
||||||
KdpManipulateStateHandler = GetContextManipulateHandler;
|
KdpManipulateStateHandler = GetContextManipulateHandler;
|
||||||
|
/* We can now send data, since after this we will be connected to GDB */
|
||||||
|
CanSendData = TRUE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* FIXME */
|
/* FIXME */
|
||||||
|
@ -159,6 +162,9 @@ send_kd_debug_io(
|
||||||
_In_ DBGKD_DEBUG_IO* DebugIO,
|
_In_ DBGKD_DEBUG_IO* DebugIO,
|
||||||
_In_ PSTRING String)
|
_In_ PSTRING String)
|
||||||
{
|
{
|
||||||
|
if (!CanSendData)
|
||||||
|
return;
|
||||||
|
|
||||||
switch (DebugIO->ApiNumber)
|
switch (DebugIO->ApiNumber)
|
||||||
{
|
{
|
||||||
case DbgKdPrintStringApi:
|
case DbgKdPrintStringApi:
|
||||||
|
|
Loading…
Reference in a new issue