#include "kdgdb.h"
+#include <pstypes.h>
+
/* LOCALS *********************************************************************/
static HANDLE gdb_run_thread;
-static HANDLE gdb_dbg_process;
+/* 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;
-CONTEXT CurrentContext;
/* PRIVATE FUNCTIONS **********************************************************/
static
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;
}
}
+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)
/* q* packets */
static
-void
-handle_gdb_query(void)
+KDSTATUS
+handle_gdb_query(
+ _Out_ DBGKD_MANIPULATE_STATE64* State,
+ _Out_ PSTRING MessageData,
+ _Out_ PULONG MessageLength,
+ _Inout_ PKD_CONTEXT KdContext)
{
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)
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, "qTStatus", 8) == 0)
+ if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0)
+ || (strncmp(gdb_input, "qsThreadInfo", 12) == 0))
{
- /* We don't support tracepoints. */
- send_gdb_packet("T0");
- return;
+ LIST_ENTRY* ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer;
+ BOOLEAN FirstThread = TRUE;
+ PEPROCESS Process;
+ PETHREAD Thread;
+ char gdb_out[1024];
+ char* ptr;
+ BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0;
+
+ /* Maybe this was not initialized yet */
+ if (!ProcessListHead->Flink)
+ {
+ char gdb_out[64];
+
+ if (Resuming)
+ {
+ /* there is only one thread to tell about */
+ send_gdb_packet("l");
+ 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 */
+ return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
+ }
+
+ if (Resuming)
+ {
+ if (CurrentThreadEntry == NULL)
+ CurrentProcessEntry = CurrentProcessEntry->Flink;
+ }
+ else
+ CurrentProcessEntry = ProcessListHead->Flink;
+
+ if (CurrentProcessEntry == ProcessListHead)
+ {
+ /* We're done */
+ send_gdb_packet("l");
+ return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
+ }
+
+ Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
+
+ if (Resuming && CurrentThreadEntry != NULL)
+ CurrentThreadEntry = CurrentThreadEntry->Flink;
+ else
+ CurrentThreadEntry = Process->ThreadListHead.Flink;
+
+ ptr = gdb_out;
+
+ *ptr++ = 'm';
+ /* List threads from this process */
+ for ( ;
+ CurrentThreadEntry != &Process->ThreadListHead;
+ CurrentThreadEntry = CurrentThreadEntry->Flink)
+ {
+ Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry);
+
+ /* See if we should add a comma */
+ if (FirstThread)
+ {
+ FirstThread = FALSE;
+ }
+ else
+ {
+ *ptr++ = ',';
+ }
+
+ ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
+ "p%p.%p", PsGetProcessId(Process), PsGetThreadId(Thread));
+ if (ptr > (gdb_out + 1024))
+ {
+ /* send what we got */
+ send_gdb_packet(gdb_out);
+ /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
+ return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
+ }
+ }
+
+ /* send the list for this process */
+ send_gdb_packet(gdb_out);
+ CurrentThreadEntry = NULL;
+ /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
+ 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
#endif
static
-KDSTATUS
-handle_gdb_read_mem(
- _Out_ DBGKD_MANIPULATE_STATE64* State,
- _Out_ PSTRING MessageData,
- _Out_ PULONG MessageLength)
-{
- State->ApiNumber = DbgKdReadVirtualMemoryApi;
- State->ReturnStatus = STATUS_SUCCESS; /* ? */
- State->Processor = CurrentStateChange.Processor;
- State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
- if (MessageData)
- MessageData->Length = 0;
- *MessageLength = 0;
-
- State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
- State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
- return KdPacketReceived;
-}
-
-static
-VOID
-GetCurrentContextSendHandler(
+void
+ReadMemorySendHandler(
_In_ ULONG PacketType,
_In_ PSTRING MessageHeader,
- _In_ PSTRING MessageData
-)
+ _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)))
+ if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
{
- /* Should we bugcheck ? */
+ // KdAssert
+ KDDBGPRINT("Wrong packet type (%lu) received after DbgKdReadVirtualMemoryApi request.\n", PacketType);
while (1);
}
- /* Just copy it */
- RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
-}
-
-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))
+ if (State->ApiNumber != DbgKdReadVirtualMemoryApi)
{
- /* Should we bugcheck ? */
- while (1);
+ KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State->ApiNumber);
}
-}
-
-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;
+ /* Check status */
+ if (!NT_SUCCESS(State->ReturnStatus))
+ send_gdb_ntstatus(State->ReturnStatus);
+ else
+ send_gdb_memory(MessageData->Buffer, MessageData->Length);
+ KdpSendPacketHandler = NULL;
+ KdpManipulateStateHandler = NULL;
}
static
KDSTATUS
-SendContinue(
+handle_gdb_read_mem(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
- _Out_ PULONG MessageLength,
- _Inout_ PKD_CONTEXT KdContext
-)
+ _Out_ PULONG MessageLength)
{
- /* Let's go on */
- State->ApiNumber = DbgKdContinueApi;
+ State->ApiNumber = DbgKdReadVirtualMemoryApi;
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;
+ State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
+ State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
- /* So we must get past the breakpoint instruction */
- ProgramCounter = KdpGetContextPc(&CurrentContext);
- KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
+ /* KD will reply with KdSendPacket. Catch it */
+ KdpSendPacketHandler = ReadMemorySendHandler;
- /* Set the context and continue */
- SetContext(State, MessageData, MessageLength, KdContext, SendContinue);
return KdPacketReceived;
}
{
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;
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;
}
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{
- KDSTATUS Status;
switch (gdb_input[0])
{
case '?':
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();
- break;
+ return handle_gdb_query(State, MessageData, MessageLength, KdContext);
case 'T':
handle_gdb_thread_alive();
break;
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);
}