mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 09:25:10 +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 *********************************************************************/
|
||||
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':
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "kdgdb.h"
|
||||
|
||||
#include <pstypes.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue