- As pid and tid 0 have a special meaning in GDB, use off-by-one thread and process ID when communicating with it
 - Properly read registers and memory from foreign thread and processes. (This time it was tested and proved to work reliably. __writecr3 ftw!)
 - Loop the list of processes and threads when trying to find them from ID, as PsLookupProessByThreadId and friends can't be used since we can be at any IRQL.
 - Add a few more debug prints to help diagnosing problems.
CORE-8531

svn path=/trunk/; revision=64166
This commit is contained in:
Jérôme Gardou 2014-09-15 22:05:21 +00:00
parent 000f227784
commit de914f2aed
7 changed files with 263 additions and 126 deletions

View file

@ -7,6 +7,7 @@ list(APPEND SOURCE
gdb_send.c gdb_send.c
kdcom.c kdcom.c
kdpacket.c kdpacket.c
utils.c
kdgdb.h) kdgdb.h)
# TODO: AMD64, ARM... # TODO: AMD64, ARM...

View file

@ -7,24 +7,20 @@
#include "kdgdb.h" #include "kdgdb.h"
#include <pstypes.h>
/* LOCALS *********************************************************************/ /* LOCALS *********************************************************************/
static HANDLE gdb_run_thread; static ULONG_PTR gdb_run_tid;
/* 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;
/* GLOBALS ********************************************************************/ /* GLOBALS ********************************************************************/
HANDLE gdb_dbg_process; UINT_PTR gdb_dbg_pid;
HANDLE gdb_dbg_thread; UINT_PTR gdb_dbg_tid;
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
static static
HANDLE UINT_PTR
hex_to_thread(char* buffer) hex_to_tid(char* buffer)
{ {
ULONG_PTR ret = 0; ULONG_PTR ret = 0;
char hex; char hex;
@ -32,12 +28,13 @@ hex_to_thread(char* buffer)
{ {
hex = hex_value(*buffer++); hex = hex_value(*buffer++);
if (hex < 0) if (hex < 0)
return (HANDLE)ret; return ret;
ret <<= 4; ret <<= 4;
ret += hex; ret += hex;
} }
return (HANDLE)ret; return ret;
} }
#define hex_to_pid hex_to_tid
static static
ULONG64 ULONG64
@ -65,26 +62,26 @@ handle_gdb_set_thread(void)
{ {
case 'c': case 'c':
if (strcmp(&gdb_input[2], "-1") == 0) if (strcmp(&gdb_input[2], "-1") == 0)
gdb_run_thread = (HANDLE)-1; gdb_run_tid = (ULONG_PTR)-1;
else else
gdb_run_thread = hex_to_thread(&gdb_input[2]); gdb_run_tid = hex_to_tid(&gdb_input[2]);
send_gdb_packet("OK"); send_gdb_packet("OK");
break; break;
case 'g': case 'g':
KDDBGPRINT("Setting debug thread: %s.\n", gdb_input); KDDBGPRINT("Setting debug thread: %s.\n", gdb_input);
if (strncmp(&gdb_input[2], "p-1", 3) == 0) if (strncmp(&gdb_input[2], "p-1", 3) == 0)
{ {
gdb_dbg_process = (HANDLE)-1; gdb_dbg_pid = (UINT_PTR)-1;
gdb_dbg_thread = (HANDLE)-1; gdb_dbg_tid = (UINT_PTR)-1;
} }
else else
{ {
char* ptr = strstr(gdb_input, ".") + 1; char* ptr = strstr(gdb_input, ".") + 1;
gdb_dbg_process = hex_to_thread(&gdb_input[3]); gdb_dbg_pid = hex_to_pid(&gdb_input[3]);
if (strncmp(ptr, "-1", 2) == 0) if (strncmp(ptr, "-1", 2) == 0)
gdb_dbg_thread = (HANDLE)-1; gdb_dbg_tid = (UINT_PTR)-1;
else else
gdb_dbg_thread = hex_to_thread(ptr); gdb_dbg_tid = hex_to_tid(ptr);
} }
send_gdb_packet("OK"); send_gdb_packet("OK");
break; break;
@ -112,26 +109,22 @@ static
void void
handle_gdb_thread_alive(void) handle_gdb_thread_alive(void)
{ {
char* ptr = strstr(gdb_input, ".") + 1; ULONG_PTR Pid, Tid;
CLIENT_ID ClientId;
PETHREAD Thread; PETHREAD Thread;
NTSTATUS Status;
ClientId.UniqueProcess = hex_to_thread(&gdb_input[2]); Pid = hex_to_pid(&gdb_input[2]);
ClientId.UniqueThread = hex_to_thread(ptr); Tid = hex_to_tid(strstr(gdb_input, ".") + 1);
Status = PsLookupProcessThreadByCid(&ClientId, NULL, &Thread); /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
* So loop. */
KDDBGPRINT("Checking if p%p.%p is alive.\n", Pid, Tid);
if (!NT_SUCCESS(Status)) Thread = find_thread(Pid, Tid);
{
/* Thread doesn't exist */ if (Thread != NULL)
send_gdb_packet("OK");
else
send_gdb_packet("E03"); send_gdb_packet("E03");
return;
}
/* It's OK */
ObDereferenceObject(Thread);
send_gdb_packet("OK");
} }
/* q* packets */ /* q* packets */
@ -165,9 +158,9 @@ handle_gdb_query(
if (strcmp(gdb_input, "qC") == 0) if (strcmp(gdb_input, "qC") == 0)
{ {
char gdb_out[64]; char gdb_out[64];
sprintf(gdb_out, "QC:p%p.%p;", sprintf(gdb_out, "QC:p%"PRIxPTR".%"PRIxPTR";",
PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread), handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)),
PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)); handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
send_gdb_packet(gdb_out); send_gdb_packet(gdb_out);
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
} }
@ -175,44 +168,35 @@ handle_gdb_query(
if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0) if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0)
|| (strncmp(gdb_input, "qsThreadInfo", 12) == 0)) || (strncmp(gdb_input, "qsThreadInfo", 12) == 0))
{ {
LIST_ENTRY* ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer;
BOOLEAN FirstThread = TRUE; BOOLEAN FirstThread = TRUE;
PEPROCESS Process; PEPROCESS Process;
PETHREAD Thread; PETHREAD Thread;
char gdb_out[1024]; char gdb_out[1024];
char* ptr; char* ptr = gdb_out;
BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0; 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 (Resuming)
{ {
if (CurrentProcessEntry == (LIST_ENTRY*)1)
{
/* We're done */
send_gdb_packet("l");
CurrentProcessEntry = NULL;
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
}
if (CurrentThreadEntry == NULL) if (CurrentThreadEntry == NULL)
CurrentProcessEntry = CurrentProcessEntry->Flink; CurrentProcessEntry = CurrentProcessEntry->Flink;
} }
else else
CurrentProcessEntry = ProcessListHead->Flink; CurrentProcessEntry = ProcessListHead->Flink;
if (CurrentProcessEntry == ProcessListHead) if ((CurrentProcessEntry == ProcessListHead) ||
(CurrentProcessEntry == NULL)) /* Ps is not initialized */
{ {
/* We're done */ /* We're almost done. Tell GDB about the idle thread */
send_gdb_packet("l"); send_gdb_packet("mp1.1");
CurrentProcessEntry = (LIST_ENTRY*)1;
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
} }
@ -244,7 +228,9 @@ handle_gdb_query(
} }
ptr += _snprintf(ptr, 1024 - (ptr - gdb_out), ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
"p%p.%p", PsGetProcessId(Process), PsGetThreadId(Thread)); "p%p.%p",
handle_to_gdb_pid(Process->UniqueProcessId),
handle_to_gdb_tid(Thread->Cid.UniqueThread));
if (ptr > (gdb_out + 1024)) if (ptr > (gdb_out + 1024))
{ {
/* send what we got */ /* send what we got */
@ -319,11 +305,10 @@ ReadMemorySendHandler(
KdpSendPacketHandler = NULL; KdpSendPacketHandler = NULL;
KdpManipulateStateHandler = NULL; KdpManipulateStateHandler = NULL;
/* Detach if we have to */ /* Reset the TLB */
if (AttachedProcess != NULL) if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
{ {
KeDetachProcess(); __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
AttachedProcess = NULL;
} }
} }
@ -343,17 +328,17 @@ handle_gdb_read_mem(
MessageData->Length = 0; MessageData->Length = 0;
*MessageLength = 0; *MessageLength = 0;
/* Attach to the debug process to read its memory */ /* Set the TLB according to the process being read. Pid 0 means any process. */
if (gdb_dbg_process != PsGetCurrentProcessId()) if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
{ {
NTSTATUS Status = PsLookupProcessByProcessId(gdb_dbg_process, &AttachedProcess); PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
if (!NT_SUCCESS(Status)) if (AttachedProcess == NULL)
{ {
KDDBGPRINT("The current GDB debug thread is invalid!"); KDDBGPRINT("The current GDB debug thread is invalid!");
send_gdb_packet("E03"); send_gdb_packet("E03");
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
} }
KeAttachProcess(&AttachedProcess->Pcb); __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
} }
State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]); State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);

View file

@ -168,15 +168,22 @@ gdb_send_exception(void)
{ {
char gdb_out[1024]; char gdb_out[1024];
char* ptr = gdb_out; char* ptr = gdb_out;
DBGKM_EXCEPTION64* Exception = &CurrentStateChange.u.Exception; PETHREAD Thread = (PETHREAD)(ULONG_PTR)CurrentStateChange.Thread;
/* Report to GDB */ /* Report to GDB */
*ptr++ = 'T'; *ptr++ = 'T';
ptr = exception_code_to_gdb(Exception->ExceptionRecord.ExceptionCode, ptr); if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
ptr += sprintf(ptr, "thread:p%p.%p;", {
PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread), EXCEPTION_RECORD64* ExceptionRecord = &CurrentStateChange.u.Exception.ExceptionRecord;
PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)); ptr = exception_code_to_gdb(ExceptionRecord->ExceptionCode, ptr);
}
else
ptr += sprintf(ptr, "05");
ptr += sprintf(ptr, "thread:p%" PRIxPTR ".%" PRIxPTR ";",
handle_to_gdb_pid(PsGetThreadProcessId(Thread)),
handle_to_gdb_tid(PsGetThreadId(Thread)));
ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor); ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
send_gdb_packet(gdb_out); send_gdb_packet(gdb_out);
} }

View file

@ -7,8 +7,6 @@
#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,
@ -85,36 +83,62 @@ static
void* void*
thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size) thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size)
{ {
PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame; /* See if the guy got a stack */
if (Thread->Tcb.InitialStack == NULL)
/* See if the thread was actually scheduled */
if (TrapFrame == NULL)
{ {
return NULL; static const void* NullValue = NULL;
/* Terminated thread ? */
switch (reg_name)
{
case ESP:
case EBP:
case EIP:
*size = 4;
return &NullValue;
default:
return NULL;
}
} }
else if (Thread->Tcb.TrapFrame)
*size = 4;
switch (reg_name)
{ {
case EAX: return &TrapFrame->Eax; PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame;
case ECX: return &TrapFrame->Ecx;
case EDX: return &TrapFrame->Edx; *size = 4;
case EBX: return &TrapFrame->Ebx; switch (reg_name)
case ESP: return (TrapFrame->PreviousPreviousMode == KernelMode) ? {
&TrapFrame->TempEsp : &TrapFrame->HardwareEsp; case EAX: return &TrapFrame->Eax;
case EBP: return &TrapFrame->Ebp; case ECX: return &TrapFrame->Ecx;
case ESI: return &TrapFrame->Esi; case EDX: return &TrapFrame->Edx;
case EDI: return &TrapFrame->Edi; case EBX: return &TrapFrame->Ebx;
case EIP: return &TrapFrame->Eip; case ESP: return (TrapFrame->PreviousPreviousMode == KernelMode) ?
case EFLAGS: return &TrapFrame->EFlags; &TrapFrame->TempEsp : &TrapFrame->HardwareEsp;
case CS: return &TrapFrame->SegCs; case EBP: return &TrapFrame->Ebp;
case SS: return &TrapFrame->HardwareSegSs; case ESI: return &TrapFrame->Esi;
case DS: return &TrapFrame->SegDs; case EDI: return &TrapFrame->Edi;
case ES: return &TrapFrame->SegEs; case EIP: return &TrapFrame->Eip;
case FS: return &TrapFrame->SegFs; case EFLAGS: return &TrapFrame->EFlags;
case GS: return &TrapFrame->SegGs; case CS: return &TrapFrame->SegCs;
default: case SS: return &TrapFrame->HardwareSegSs;
KDDBGPRINT("Unhandled regname: %d.\n", reg_name); 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);
}
}
else
{
/* The thread was not yet scheduled */
*size = 4;
switch(reg_name)
{
case ESP: return &Thread->Tcb.KernelStack;
case EBP: return &((ULONG*)Thread->Tcb.KernelStack)[4];
case EIP: return &Thread->StartAddress;
default:
return NULL;
}
} }
return NULL; return NULL;
} }
@ -132,7 +156,10 @@ gdb_send_registers(
unsigned short size; unsigned short size;
CHAR* ptr = Registers; CHAR* ptr = Registers;
if (gdb_dbg_thread == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)) KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
{ {
for(i=0; i < 16; i++) for(i=0; i < 16; i++)
{ {
@ -150,10 +177,10 @@ gdb_send_registers(
else else
{ {
PETHREAD DbgThread; PETHREAD DbgThread;
NTSTATUS Status;
Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread); DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
if (!NT_SUCCESS(Status))
if (DbgThread == NULL)
{ {
/* Thread is dead */ /* Thread is dead */
send_gdb_packet("E03"); send_gdb_packet("E03");
@ -199,7 +226,8 @@ 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]);
if (gdb_dbg_thread == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)) if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
{ {
/* We can get it from the context of the current exception */ /* We can get it from the context of the current exception */
ptr = ctx_to_reg(&CurrentContext, reg_name, &size); ptr = ctx_to_reg(&CurrentContext, reg_name, &size);
@ -207,10 +235,10 @@ gdb_send_register(
else else
{ {
PETHREAD DbgThread; PETHREAD DbgThread;
NTSTATUS Status;
Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread); DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
if (!NT_SUCCESS(Status))
if (DbgThread == NULL)
{ {
/* Thread is dead */ /* Thread is dead */
send_gdb_packet("E03"); send_gdb_packet("E03");

View file

@ -13,9 +13,12 @@
#include <halfuncs.h> #include <halfuncs.h>
#include <stdio.h> #include <stdio.h>
#include <arc/arc.h> #include <arc/arc.h>
#include <inttypes.h>
#include <windbgkd.h> #include <windbgkd.h>
#include <kddll.h> #include <kddll.h>
#include <pstypes.h>
#define KDDEBUG /* uncomment to enable debugging this dll */ #define KDDEBUG /* uncomment to enable debugging this dll */
#ifndef KDDEBUG #ifndef KDDEBUG
@ -25,6 +28,18 @@ extern ULONG KdpDbgPrint(const char* Format, ...);
#define KDDBGPRINT KdpDbgPrint #define KDDBGPRINT KdpDbgPrint
#endif #endif
/* GDB doesn't like pid - tid 0, so +1 them */
FORCEINLINE HANDLE gdb_tid_to_handle(UINT_PTR Tid)
{
return (HANDLE)(Tid - 1);
}
#define gdb_pid_to_handle gdb_tid_to_handle
FORCEINLINE UINT_PTR handle_to_gdb_tid(HANDLE Handle)
{
return (UINT_PTR)Handle + 1;
}
#define handle_to_gdb_pid handle_to_gdb_tid
FORCEINLINE FORCEINLINE
VOID VOID
InitManipulateFromStateChange( InitManipulateFromStateChange(
@ -51,8 +66,8 @@ typedef KDSTATUS (*KDP_MANIPULATESTATE_HANDLER)(
); );
/* gdb_input.c */ /* gdb_input.c */
extern HANDLE gdb_dbg_thread; extern UINT_PTR gdb_dbg_tid;
extern HANDLE gdb_dbg_process; extern UINT_PTR gdb_dbg_pid;
extern KDSTATUS gdb_interpret_input(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext); 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); extern KDSTATUS gdb_receive_and_interpret_packet(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
@ -79,11 +94,18 @@ extern DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
extern CONTEXT CurrentContext; extern CONTEXT CurrentContext;
extern DBGKD_GET_VERSION64 KdVersion; extern DBGKD_GET_VERSION64 KdVersion;
extern KDDEBUGGER_DATA64* KdDebuggerDataBlock; extern KDDEBUGGER_DATA64* KdDebuggerDataBlock;
extern LIST_ENTRY* ProcessListHead;
extern KDP_SEND_HANDLER KdpSendPacketHandler; extern KDP_SEND_HANDLER KdpSendPacketHandler;
extern KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler; extern KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler;
/* Commone ManipulateState handlers */ /* Commone ManipulateState handlers */
extern KDSTATUS ContinueManipulateStateHandler(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext); 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); extern KDSTATUS SetContextManipulateHandler(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
extern PEPROCESS TheIdleProcess;
extern PETHREAD TheIdleThread;
/* utils.c */
extern PEPROCESS find_process( _In_ UINT_PTR Pid);
extern PETHREAD find_thread(_In_ UINT_PTR Pid, _In_ UINT_PTR Tid);
/* arch_sup.c */ /* arch_sup.c */
extern KDSTATUS gdb_send_register(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext); extern KDSTATUS gdb_send_register(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);

View file

@ -14,18 +14,20 @@ FirstSendHandler(
_In_ ULONG PacketType, _In_ ULONG PacketType,
_In_ PSTRING MessageHeader, _In_ PSTRING MessageHeader,
_In_ PSTRING MessageData); _In_ PSTRING MessageData);
static BOOLEAN CanSendData = FALSE; static BOOLEAN InException = FALSE;
/* GLOBALS ********************************************************************/ /* GLOBALS ********************************************************************/
DBGKD_GET_VERSION64 KdVersion; DBGKD_GET_VERSION64 KdVersion;
KDDEBUGGER_DATA64* KdDebuggerDataBlock; KDDEBUGGER_DATA64* KdDebuggerDataBlock;
BOOLEAN InException = FALSE; LIST_ENTRY* ProcessListHead;
/* Callbacks used to communicate with KD aside from GDB */ /* Callbacks used to communicate with KD aside from GDB */
KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler; KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler;
KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL; KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
/* Data describing the current exception */ /* Data describing the current exception */
DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange; DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
CONTEXT CurrentContext; CONTEXT CurrentContext;
PEPROCESS TheIdleProcess;
PETHREAD TheIdleThread;
/* PRIVATE FUNCTIONS **********************************************************/ /* PRIVATE FUNCTIONS **********************************************************/
@ -130,6 +132,8 @@ static
void void
send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange) send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
{ {
InException = TRUE;
switch (StateChange->NewState) switch (StateChange->NewState)
{ {
case DbgKdLoadSymbolsStateChange: case DbgKdLoadSymbolsStateChange:
@ -139,17 +143,22 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
break; break;
} }
case DbgKdExceptionStateChange: case DbgKdExceptionStateChange:
{
PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
/* 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 */ KDDBGPRINT("Exception 0x%08x in thread p%p.%p.\n",
gdb_dbg_thread = PsGetThreadId((PETHREAD)(ULONG_PTR)StateChange->Thread); StateChange->u.Exception.ExceptionRecord.ExceptionCode,
gdb_dbg_process = PsGetThreadProcessId((PETHREAD)(ULONG_PTR)StateChange->Thread); PsGetThreadProcessId(Thread),
PsGetThreadId(Thread));
/* Set the current debugged process/thread accordingly */
gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(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 */
while (1); while (1);
@ -162,7 +171,7 @@ send_kd_debug_io(
_In_ DBGKD_DEBUG_IO* DebugIO, _In_ DBGKD_DEBUG_IO* DebugIO,
_In_ PSTRING String) _In_ PSTRING String)
{ {
if (!CanSendData) if (InException)
return; return;
switch (DebugIO->ApiNumber) switch (DebugIO->ApiNumber)
@ -217,6 +226,9 @@ ContinueManipulateStateHandler(
/* We definitely are at the end of the send <-> receive loop, if any */ /* We definitely are at the end of the send <-> receive loop, if any */
KdpSendPacketHandler = NULL; KdpSendPacketHandler = NULL;
KdpManipulateStateHandler = NULL; KdpManipulateStateHandler = NULL;
/* We're not handling an exception anymore */
InException = FALSE;
return KdPacketReceived; return KdPacketReceived;
} }
@ -244,10 +256,11 @@ GetVersionSendHandler(
RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion)); RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList; DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List); KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer;
/* We can tell KD to continue */ /* Now we can get the context for the current state */
KdpSendPacketHandler = NULL; KdpSendPacketHandler = NULL;
KdpManipulateStateHandler = ContinueManipulateStateHandler; KdpManipulateStateHandler = GetContextManipulateHandler;
} }
static static
@ -267,9 +280,6 @@ GetVersionManipulateStateHandler(
KdpSendPacketHandler = GetVersionSendHandler; KdpSendPacketHandler = GetVersionSendHandler;
KdpManipulateStateHandler = NULL; KdpManipulateStateHandler = NULL;
/* This will make KD breakin and we will be able to properly attach to GDB */
KdContext->KdpControlCPending = TRUE;
return KdPacketReceived; return KdPacketReceived;
} }
@ -281,6 +291,7 @@ FirstSendHandler(
_In_ PSTRING MessageData) _In_ PSTRING MessageData)
{ {
DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer; DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer;
PETHREAD Thread;
if (PacketType == PACKET_TYPE_KD_DEBUG_IO) if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
{ {
@ -296,7 +307,19 @@ FirstSendHandler(
while(1); while(1);
} }
KDDBGPRINT("KDGDB: START!\n");
Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
/* Set up the current state */
CurrentStateChange = *StateChange; CurrentStateChange = *StateChange;
gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
/* This is the idle process. Save it! */
TheIdleThread = Thread;
TheIdleProcess = (PEPROCESS)Thread->Tcb.ApcState.Process;
KDDBGPRINT("Pid Tid of the first message: %" PRIxPTR", %" PRIxPTR ".\n", gdb_dbg_pid, gdb_dbg_tid);
/* The next receive call will be asking for the version data */ /* The next receive call will be asking for the version data */
KdpSendPacketHandler = NULL; KdpSendPacketHandler = NULL;

View file

@ -0,0 +1,71 @@
/*
* COPYRIGHT: GPL, see COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/base/kddll/utils.c
* PURPOSE: Misc helper functions.
*/
#include "kdgdb.h"
/*
* We cannot use PsLookupProcessThreadByCid or alike as we could be running at any IRQL.
* So we have to loop over the process list.
*/
PEPROCESS
find_process(
_In_ UINT_PTR Pid)
{
HANDLE ProcessId = gdb_pid_to_handle(Pid);
LIST_ENTRY* ProcessEntry;
PEPROCESS Process;
/* Special case for idle process */
if (Pid == 1)
return TheIdleProcess;
for (ProcessEntry = ProcessListHead->Flink;
ProcessEntry != ProcessListHead;
ProcessEntry = ProcessEntry->Flink)
{
Process = CONTAINING_RECORD(ProcessEntry, EPROCESS, ActiveProcessLinks);
if (Process->UniqueProcessId == ProcessId)
return Process;
}
return NULL;
}
PETHREAD
find_thread(
_In_ UINT_PTR Pid,
_In_ UINT_PTR Tid)
{
HANDLE ThreadId = gdb_tid_to_handle(Tid);
PETHREAD Thread;
PEPROCESS Process;
LIST_ENTRY* ThreadEntry;
/* Special case for the idle thread */
if ((Pid == 1) && (Tid == 1))
return TheIdleThread;
Process = find_process(Pid);
if (!Process)
return NULL;
for (ThreadEntry = Process->ThreadListHead.Flink;
ThreadEntry != &Process->ThreadListHead;
ThreadEntry = ThreadEntry->Flink)
{
Thread = CONTAINING_RECORD(ThreadEntry, ETHREAD, ThreadListEntry);
/* For GDB, Tid == 0 means any thread */
if ((Thread->Cid.UniqueThread == ThreadId) || (Tid == 0))
{
return Thread;
}
}
return NULL;
}