mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 19:26:32 +00:00
[KDGDB]
- Always pass down the result of gdb_receive_packet up to KD, so that it knows when a breakin packet was received. (CTRL-C) now works! - Generalize the use of the Send <-> ManipulateState callbacks for a better code reading. - Get the exception context as soon as it is thrown (instead of playing with the PRCB) - Improve the way we attach to GDB: on the first KD call, we set KdContext->ControlCPending so that KD throws an exception. That way we can first initialize our KD stuff, and then quietly attach to GDB - Implement the 'p' (get one register) GDB request. GDB is now much more reliable. svn path=/trunk/; revision=64154
This commit is contained in:
@@ -11,13 +11,14 @@
|
||||
|
||||
/* LOCALS *********************************************************************/
|
||||
static HANDLE gdb_run_thread;
|
||||
static HANDLE gdb_dbg_process;
|
||||
HANDLE gdb_dbg_thread;
|
||||
CONTEXT CurrentContext;
|
||||
/* Keep track of where we are for qfThreadInfo/qsThreadInfo */
|
||||
static LIST_ENTRY* CurrentProcessEntry;
|
||||
static LIST_ENTRY* CurrentThreadEntry;
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
HANDLE gdb_dbg_process;
|
||||
HANDLE gdb_dbg_thread;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
static
|
||||
HANDLE
|
||||
@@ -68,6 +69,7 @@ handle_gdb_set_thread(void)
|
||||
send_gdb_packet("OK");
|
||||
break;
|
||||
case 'g':
|
||||
KDDBGPRINT("Setting debug thread: %s.\n", gdb_input);
|
||||
if (strncmp(&gdb_input[2], "p-1", 3) == 0)
|
||||
{
|
||||
gdb_dbg_process = (HANDLE)-1;
|
||||
@@ -90,6 +92,20 @@ handle_gdb_set_thread(void)
|
||||
}
|
||||
}
|
||||
|
||||
KDSTATUS
|
||||
gdb_receive_and_interpret_packet(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
KDSTATUS Status = gdb_receive_packet(KdContext);
|
||||
|
||||
if (Status != KdPacketReceived)
|
||||
return Status;
|
||||
return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
handle_gdb_thread_alive(void)
|
||||
@@ -118,7 +134,7 @@ handle_gdb_thread_alive(void)
|
||||
|
||||
/* q* packets */
|
||||
static
|
||||
void
|
||||
KDSTATUS
|
||||
handle_gdb_query(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
@@ -128,20 +144,20 @@ handle_gdb_query(
|
||||
if (strncmp(gdb_input, "qSupported:", 11) == 0)
|
||||
{
|
||||
send_gdb_packet("PacketSize=4096;multiprocess+;");
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
if (strncmp(gdb_input, "qAttached", 9) == 0)
|
||||
{
|
||||
/* Say yes: the remote server didn't create the process, ReactOS did! */
|
||||
/* Say no: We didn't attach, we create the process! */
|
||||
send_gdb_packet("0");
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
if (strncmp(gdb_input, "qRcmd,", 6) == 0)
|
||||
{
|
||||
send_gdb_packet("OK");
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
if (strcmp(gdb_input, "qC") == 0)
|
||||
@@ -151,7 +167,7 @@ handle_gdb_query(
|
||||
PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread),
|
||||
PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
|
||||
send_gdb_packet(gdb_out);
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0)
|
||||
@@ -174,15 +190,13 @@ handle_gdb_query(
|
||||
{
|
||||
/* there is only one thread to tell about */
|
||||
send_gdb_packet("l");
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
/* Just tell GDB about the current thread */
|
||||
sprintf(gdb_out, "mp%p.%p", PsGetCurrentProcessId(), PsGetCurrentThreadId());
|
||||
send_gdb_packet(gdb_out);
|
||||
/* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
|
||||
gdb_receive_packet(KdContext);
|
||||
gdb_interpret_input(State, MessageData, MessageLength, KdContext);
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
if (Resuming)
|
||||
@@ -197,7 +211,7 @@ handle_gdb_query(
|
||||
{
|
||||
/* We're done */
|
||||
send_gdb_packet("l");
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
|
||||
@@ -234,9 +248,7 @@ handle_gdb_query(
|
||||
/* send what we got */
|
||||
send_gdb_packet(gdb_out);
|
||||
/* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
|
||||
gdb_receive_packet(KdContext);
|
||||
gdb_interpret_input(State, MessageData, MessageLength, KdContext);
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,13 +256,12 @@ handle_gdb_query(
|
||||
send_gdb_packet(gdb_out);
|
||||
CurrentThreadEntry = NULL;
|
||||
/* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
|
||||
gdb_receive_packet(KdContext);
|
||||
gdb_interpret_input(State, MessageData, MessageLength, KdContext);
|
||||
return;
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
|
||||
send_gdb_packet("");
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -304,6 +315,7 @@ ReadMemorySendHandler(
|
||||
else
|
||||
send_gdb_memory(MessageData->Buffer, MessageData->Length);
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
@@ -330,150 +342,6 @@ handle_gdb_read_mem(
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
GetCurrentContextSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData
|
||||
)
|
||||
{
|
||||
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
||||
const CONTEXT* Context = (const CONTEXT*)MessageData->Buffer;
|
||||
|
||||
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
||||
|| (State->ApiNumber != DbgKdGetContextApi)
|
||||
|| (MessageData->Length < sizeof(*Context)))
|
||||
{
|
||||
/* Should we bugcheck ? */
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Just copy it */
|
||||
RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
|
||||
KdpSendPacketHandler = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
GetCurrentContext(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext,
|
||||
_In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
|
||||
)
|
||||
{
|
||||
State->ApiNumber = DbgKdGetContextApi;
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ReturnStatus = STATUS_SUCCESS;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
MessageData->Length = 0;
|
||||
|
||||
/* Update the send <-> receive loop handler */
|
||||
KdpSendPacketHandler = GetCurrentContextSendHandler;
|
||||
KdpManipulateStateHandler = ManipulateStateHandler;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SetContextSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData
|
||||
)
|
||||
{
|
||||
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
||||
|
||||
/* We just confirm that all went well */
|
||||
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
||||
|| (State->ApiNumber != DbgKdSetContextApi)
|
||||
|| (State->ReturnStatus != STATUS_SUCCESS))
|
||||
{
|
||||
/* Should we bugcheck ? */
|
||||
while (1);
|
||||
}
|
||||
|
||||
KdpSendPacketHandler = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
SetContext(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext,
|
||||
_In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
|
||||
)
|
||||
{
|
||||
State->ApiNumber = DbgKdSetContextApi;
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ReturnStatus = STATUS_SUCCESS;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
MessageData->Length = sizeof(CurrentContext);
|
||||
|
||||
if (MessageData->MaximumLength < sizeof(CurrentContext))
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
RtlCopyMemory(MessageData->Buffer, &CurrentContext, sizeof(CurrentContext));
|
||||
|
||||
/* Update the send <-> receive loop handlers */
|
||||
KdpSendPacketHandler = SetContextSendHandler;
|
||||
KdpManipulateStateHandler = ManipulateStateHandler;
|
||||
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
SendContinue(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext
|
||||
)
|
||||
{
|
||||
/* Let's go on */
|
||||
State->ApiNumber = DbgKdContinueApi;
|
||||
State->ReturnStatus = STATUS_SUCCESS; /* ? */
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
if (MessageData)
|
||||
MessageData->Length = 0;
|
||||
*MessageLength = 0;
|
||||
State->u.Continue.ContinueStatus = STATUS_SUCCESS;
|
||||
|
||||
/* We definitely are at the end of the send <-> receive loop, if any */
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
|
||||
/* Tell GDB we are fine */
|
||||
send_gdb_packet("OK");
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
UpdateProgramCounterSendContinue(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
ULONG_PTR ProgramCounter;
|
||||
|
||||
/* So we must get past the breakpoint instruction */
|
||||
ProgramCounter = KdpGetContextPc(&CurrentContext);
|
||||
KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
|
||||
|
||||
/* Set the context and continue */
|
||||
SetContext(State, MessageData, MessageLength, KdContext, SendContinue);
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
handle_gdb_v(
|
||||
@@ -499,6 +367,9 @@ handle_gdb_v(
|
||||
{
|
||||
DBGKM_EXCEPTION64* Exception = NULL;
|
||||
|
||||
/* Tell GDB everything is fine, we will handle it */
|
||||
send_gdb_packet("OK");
|
||||
|
||||
if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
|
||||
Exception = &CurrentStateChange.u.Exception;
|
||||
|
||||
@@ -506,15 +377,22 @@ handle_gdb_v(
|
||||
if (Exception && (Exception->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
|
||||
&& (Exception->ExceptionRecord.ExceptionInformation[0] == 0))
|
||||
{
|
||||
/* So we get the context, update it and send it back */
|
||||
GetCurrentContext(State, MessageData, MessageLength, KdContext, UpdateProgramCounterSendContinue);
|
||||
ULONG_PTR ProgramCounter;
|
||||
|
||||
/* So we must get past the breakpoint instruction */
|
||||
ProgramCounter = KdpGetContextPc(&CurrentContext);
|
||||
KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
|
||||
|
||||
SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
|
||||
KdpManipulateStateHandler = ContinueManipulateStateHandler;
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
return SendContinue(State, MessageData, MessageLength, KdContext);
|
||||
return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
}
|
||||
|
||||
KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
@@ -526,7 +404,6 @@ gdb_interpret_input(
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
KDSTATUS Status;
|
||||
switch (gdb_input[0])
|
||||
{
|
||||
case '?':
|
||||
@@ -534,16 +411,16 @@ gdb_interpret_input(
|
||||
gdb_send_exception();
|
||||
break;
|
||||
case 'g':
|
||||
gdb_send_registers();
|
||||
break;
|
||||
return gdb_send_registers(State, MessageData, MessageLength, KdContext);
|
||||
case 'H':
|
||||
handle_gdb_set_thread();
|
||||
break;
|
||||
case 'm':
|
||||
return handle_gdb_read_mem(State, MessageData, MessageLength);
|
||||
case 'p':
|
||||
return gdb_send_register(State, MessageData, MessageLength, KdContext);
|
||||
case 'q':
|
||||
handle_gdb_query(State, MessageData, MessageLength, KdContext);
|
||||
break;
|
||||
return handle_gdb_query(State, MessageData, MessageLength, KdContext);
|
||||
case 'T':
|
||||
handle_gdb_thread_alive();
|
||||
break;
|
||||
@@ -552,12 +429,8 @@ gdb_interpret_input(
|
||||
default:
|
||||
/* We don't know how to handle this request. Maybe this is something for KD */
|
||||
State->ReturnStatus = STATUS_NOT_SUPPORTED;
|
||||
KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
|
||||
return KdPacketReceived;
|
||||
}
|
||||
/* Get the answer from GDB */
|
||||
Status = gdb_receive_packet(KdContext);
|
||||
if (Status != KdPacketReceived)
|
||||
return Status;
|
||||
/* Try interpreting this new packet */
|
||||
return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
@@ -168,17 +168,12 @@ gdb_send_exception(void)
|
||||
{
|
||||
char gdb_out[1024];
|
||||
char* ptr = gdb_out;
|
||||
DBGKM_EXCEPTION64* Exception = NULL;
|
||||
|
||||
if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
|
||||
Exception = &CurrentStateChange.u.Exception;
|
||||
DBGKM_EXCEPTION64* Exception = &CurrentStateChange.u.Exception;
|
||||
|
||||
/* Report to GDB */
|
||||
*ptr++ = 'T';
|
||||
if (Exception)
|
||||
ptr = exception_code_to_gdb(Exception->ExceptionRecord.ExceptionCode, ptr);
|
||||
else
|
||||
ptr += sprintf(ptr, "05");
|
||||
|
||||
ptr = exception_code_to_gdb(Exception->ExceptionRecord.ExceptionCode, ptr);
|
||||
ptr += sprintf(ptr, "thread:p%p.%p;",
|
||||
PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread),
|
||||
PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
|
||||
|
||||
@@ -79,21 +79,48 @@ ctx_to_reg(CONTEXT* ctx, enum reg_name name, unsigned short* size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gdb_send_registers(void)
|
||||
KDSTATUS
|
||||
gdb_send_registers(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
CONTEXT* ctx;
|
||||
PKPRCB* ProcessorBlockLists;
|
||||
ULONG32 Registers[16];
|
||||
unsigned i;
|
||||
unsigned short size;
|
||||
|
||||
ProcessorBlockLists = (PKPRCB*)KdDebuggerDataBlock->KiProcessorBlock.Pointer;
|
||||
ctx = (CONTEXT*)((char*)ProcessorBlockLists[CurrentStateChange.Processor] + KdDebuggerDataBlock->OffsetPrcbProcStateContext);
|
||||
|
||||
for(i=0; i < 16; i++)
|
||||
{
|
||||
Registers[i] = *(ULONG32*)ctx_to_reg(ctx, i, &size);
|
||||
Registers[i] = *(ULONG32*)ctx_to_reg(&CurrentContext, i, &size);
|
||||
}
|
||||
send_gdb_memory(Registers, sizeof(Registers));
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
KDSTATUS
|
||||
gdb_send_register(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
enum reg_name reg_name;
|
||||
void *ptr;
|
||||
unsigned short size;
|
||||
|
||||
/* 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 (!ptr)
|
||||
{
|
||||
/* Undefined. Let's assume 32 bit register */
|
||||
send_gdb_packet("xxxxxxxx");
|
||||
}
|
||||
else
|
||||
{
|
||||
send_gdb_memory(ptr, size);
|
||||
}
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,18 @@ extern ULONG KdpDbgPrint(const char* Format, ...);
|
||||
#define KDDBGPRINT KdpDbgPrint
|
||||
#endif
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
InitManipulateFromStateChange(
|
||||
_In_ ULONG ApiNumber,
|
||||
_In_ const DBGKD_ANY_WAIT_STATE_CHANGE* StateChange,
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* Manipulate)
|
||||
{
|
||||
Manipulate->ApiNumber = ApiNumber;
|
||||
Manipulate->Processor = StateChange->Processor;
|
||||
Manipulate->ProcessorLevel = StateChange->ProcessorLevel;
|
||||
}
|
||||
|
||||
/* Callbacks to simulate a KdReceive <-> KdSend loop without GDB being aware of it */
|
||||
typedef VOID (*KDP_SEND_HANDLER)(
|
||||
_In_ ULONG PacketType,
|
||||
@@ -40,7 +52,9 @@ typedef KDSTATUS (*KDP_MANIPULATESTATE_HANDLER)(
|
||||
|
||||
/* gdb_input.c */
|
||||
extern HANDLE gdb_dbg_thread;
|
||||
KDSTATUS gdb_interpret_input(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
|
||||
extern HANDLE gdb_dbg_process;
|
||||
extern KDSTATUS gdb_interpret_input(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
|
||||
extern KDSTATUS gdb_receive_and_interpret_packet(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
|
||||
|
||||
/* gdb_receive.c */
|
||||
extern CHAR gdb_input[];
|
||||
@@ -61,14 +75,18 @@ KDSTATUS NTAPI KdpReceiveByte(_Out_ PUCHAR OutByte);
|
||||
|
||||
/* kdpacket.c */
|
||||
extern DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
|
||||
extern CONTEXT CurrentContext;
|
||||
extern DBGKD_GET_VERSION64 KdVersion;
|
||||
extern KDDEBUGGER_DATA64* KdDebuggerDataBlock;
|
||||
extern KDP_SEND_HANDLER KdpSendPacketHandler;
|
||||
extern KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler;
|
||||
|
||||
/* Commone ManipulateState handlers */
|
||||
extern KDSTATUS ContinueManipulateStateHandler(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
|
||||
extern KDSTATUS SetContextManipulateHandler(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
|
||||
|
||||
/* arch_sup.c */
|
||||
void gdb_send_registers(void);
|
||||
extern KDSTATUS gdb_send_register(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
|
||||
extern KDSTATUS gdb_send_registers(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
|
||||
|
||||
/* Architecture specific defines. See ntoskrnl/include/internal/arch/ke.h */
|
||||
#ifdef _M_IX86
|
||||
|
||||
@@ -7,61 +7,145 @@
|
||||
|
||||
#include "kdgdb.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
/* LOCALS *********************************************************************/
|
||||
static
|
||||
VOID
|
||||
FirstSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData);
|
||||
|
||||
DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
|
||||
/* GLOBALS ********************************************************************/
|
||||
DBGKD_GET_VERSION64 KdVersion;
|
||||
KDDEBUGGER_DATA64* KdDebuggerDataBlock;
|
||||
BOOLEAN InException = FALSE;
|
||||
/* Callbacks used to communicate with KD aside from GDB */
|
||||
KDP_SEND_HANDLER KdpSendPacketHandler = NULL;
|
||||
KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler;
|
||||
KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
|
||||
|
||||
/* LOCALS *********************************************************************/
|
||||
static BOOLEAN FakeNextManipulatePacket = FALSE;
|
||||
static DBGKD_MANIPULATE_STATE64 FakeManipulateState = {0};
|
||||
/* Data describing the current exception */
|
||||
DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
|
||||
CONTEXT CurrentContext;
|
||||
|
||||
/* PRIVATE FUNCTIONS **********************************************************/
|
||||
|
||||
static
|
||||
VOID
|
||||
GetContextSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData
|
||||
)
|
||||
{
|
||||
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
||||
const CONTEXT* Context = (const CONTEXT*)MessageData->Buffer;
|
||||
|
||||
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
||||
|| (State->ApiNumber != DbgKdGetContextApi)
|
||||
|| (MessageData->Length < sizeof(*Context)))
|
||||
{
|
||||
/* Should we bugcheck ? */
|
||||
KDDBGPRINT("ERROR: Received wrong packet from KD.\n");
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Just copy it */
|
||||
RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
|
||||
KdpSendPacketHandler = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
GetContextManipulateHandler(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext
|
||||
)
|
||||
{
|
||||
State->ApiNumber = DbgKdGetContextApi;
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ReturnStatus = STATUS_SUCCESS;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
MessageData->Length = 0;
|
||||
|
||||
/* Update the send <-> receive loop handler */
|
||||
KdpSendPacketHandler = GetContextSendHandler;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
SetContextSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData
|
||||
)
|
||||
{
|
||||
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
||||
|
||||
/* We just confirm that all went well */
|
||||
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
||||
|| (State->ApiNumber != DbgKdSetContextApi)
|
||||
|| (State->ReturnStatus != STATUS_SUCCESS))
|
||||
{
|
||||
/* Should we bugcheck ? */
|
||||
while (1);
|
||||
}
|
||||
|
||||
KdpSendPacketHandler = NULL;
|
||||
}
|
||||
|
||||
KDSTATUS
|
||||
SetContextManipulateHandler(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext
|
||||
)
|
||||
{
|
||||
State->ApiNumber = DbgKdSetContextApi;
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ReturnStatus = STATUS_SUCCESS;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
MessageData->Length = sizeof(CurrentContext);
|
||||
|
||||
if (MessageData->MaximumLength < sizeof(CurrentContext))
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
RtlCopyMemory(MessageData->Buffer, &CurrentContext, sizeof(CurrentContext));
|
||||
|
||||
/* Update the send <-> receive loop handlers */
|
||||
KdpSendPacketHandler = SetContextSendHandler;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
|
||||
{
|
||||
static BOOLEAN first = TRUE;
|
||||
|
||||
/* Save current state for later GDB queries */
|
||||
CurrentStateChange = *StateChange;
|
||||
|
||||
if (first)
|
||||
{
|
||||
/*
|
||||
* This is the first packet we receive.
|
||||
* We take this as an opportunity to connect with GDB and to
|
||||
* get the KD version block
|
||||
*/
|
||||
FakeNextManipulatePacket = TRUE;
|
||||
FakeManipulateState.ApiNumber = DbgKdGetVersionApi;
|
||||
FakeManipulateState.Processor = StateChange->Processor;
|
||||
FakeManipulateState.ProcessorLevel = StateChange->ProcessorLevel;
|
||||
FakeManipulateState.ReturnStatus = STATUS_SUCCESS;
|
||||
|
||||
first = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (StateChange->NewState)
|
||||
{
|
||||
case DbgKdLoadSymbolsStateChange:
|
||||
{
|
||||
/* We don't care about symbols loading */
|
||||
FakeNextManipulatePacket = TRUE;
|
||||
FakeManipulateState.ApiNumber = DbgKdContinueApi;
|
||||
FakeManipulateState.Processor = StateChange->Processor;
|
||||
FakeManipulateState.ProcessorLevel = StateChange->ProcessorLevel;
|
||||
FakeManipulateState.ReturnStatus = STATUS_SUCCESS;
|
||||
FakeManipulateState.u.Continue.ContinueStatus = STATUS_SUCCESS;
|
||||
KdpManipulateStateHandler = ContinueManipulateStateHandler;
|
||||
break;
|
||||
}
|
||||
case DbgKdExceptionStateChange:
|
||||
/* 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_send_exception();
|
||||
/* Next receive call will ask for the context */
|
||||
KdpManipulateStateHandler = GetContextManipulateHandler;
|
||||
break;
|
||||
default:
|
||||
/* FIXME */
|
||||
@@ -100,21 +184,119 @@ send_kd_state_manipulate(
|
||||
gdb_send_registers((CONTEXT*)MessageData->Buffer);
|
||||
return;
|
||||
#endif
|
||||
case DbgKdGetVersionApi:
|
||||
{
|
||||
LIST_ENTRY* DebuggerDataList;
|
||||
/* Simply get a copy */
|
||||
RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
|
||||
DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
|
||||
KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
/* FIXME */
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
KDSTATUS
|
||||
ContinueManipulateStateHandler(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext
|
||||
)
|
||||
{
|
||||
/* Let's go on */
|
||||
State->ApiNumber = DbgKdContinueApi;
|
||||
State->ReturnStatus = STATUS_SUCCESS; /* ? */
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
if (MessageData)
|
||||
MessageData->Length = 0;
|
||||
*MessageLength = 0;
|
||||
State->u.Continue.ContinueStatus = STATUS_SUCCESS;
|
||||
|
||||
/* We definitely are at the end of the send <-> receive loop, if any */
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
GetVersionSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData)
|
||||
{
|
||||
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
||||
LIST_ENTRY* DebuggerDataList;
|
||||
|
||||
/* Confirm that all went well */
|
||||
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
||||
|| (State->ApiNumber != DbgKdGetVersionApi)
|
||||
|| !NT_SUCCESS(State->ReturnStatus))
|
||||
{
|
||||
/* FIXME: should detach from KD and go along without debugging */
|
||||
KDDBGPRINT("Wrong packet received after asking for data.\n");
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Copy the relevant data */
|
||||
RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
|
||||
DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
|
||||
KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
|
||||
|
||||
/* We can tell KD to continue */
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = ContinueManipulateStateHandler;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
GetVersionManipulateStateHandler(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
/* Ask for the version data */
|
||||
State->ApiNumber = DbgKdGetVersionApi;
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
|
||||
/* The next send call will serve this query */
|
||||
KdpSendPacketHandler = GetVersionSendHandler;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
|
||||
/* This will make KD breakin and we will be able to properly attach to GDB */
|
||||
KdContext->KdpControlCPending = TRUE;
|
||||
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
FirstSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData)
|
||||
{
|
||||
DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer;
|
||||
|
||||
if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
|
||||
{
|
||||
/* This is not the packet we are waiting for */
|
||||
send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PacketType != PACKET_TYPE_KD_STATE_CHANGE64)
|
||||
{
|
||||
KDDBGPRINT("First KD packet is not a state change!\n");
|
||||
/* FIXME: What should we send back to KD ? */
|
||||
while(1);
|
||||
}
|
||||
|
||||
CurrentStateChange = *StateChange;
|
||||
|
||||
/* The next receive call will be asking for the version data */
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = GetVersionManipulateStateHandler;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
@@ -162,13 +344,6 @@ KdReceivePacket(
|
||||
if (KdpManipulateStateHandler != NULL)
|
||||
return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
|
||||
|
||||
if (FakeNextManipulatePacket)
|
||||
{
|
||||
FakeNextManipulatePacket = FALSE;
|
||||
*State = FakeManipulateState;
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
/* Receive data from GDB */
|
||||
Status = gdb_receive_packet(KdContext);
|
||||
if (Status != KdPacketReceived)
|
||||
|
||||
Reference in New Issue
Block a user