From: Jérôme Gardou Date: Mon, 15 Sep 2014 22:05:21 +0000 (+0000) Subject: [KDGDB] X-Git-Tag: backups/0.3.17@66124~560 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=de914f2aed69dcd0d692b97730c3301495d377a9 [KDGDB] - 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 --- diff --git a/reactos/drivers/base/kdgdb/CMakeLists.txt b/reactos/drivers/base/kdgdb/CMakeLists.txt index cf180c1a680..bb9236c956d 100644 --- a/reactos/drivers/base/kdgdb/CMakeLists.txt +++ b/reactos/drivers/base/kdgdb/CMakeLists.txt @@ -7,6 +7,7 @@ list(APPEND SOURCE gdb_send.c kdcom.c kdpacket.c + utils.c kdgdb.h) # TODO: AMD64, ARM... diff --git a/reactos/drivers/base/kdgdb/gdb_input.c b/reactos/drivers/base/kdgdb/gdb_input.c index b858a381e0d..115d6804245 100644 --- a/reactos/drivers/base/kdgdb/gdb_input.c +++ b/reactos/drivers/base/kdgdb/gdb_input.c @@ -7,24 +7,20 @@ #include "kdgdb.h" -#include - /* LOCALS *********************************************************************/ -static HANDLE gdb_run_thread; -/* We might have to attach to a process to read its memory */ -static PEPROCESS AttachedProcess = NULL; +static ULONG_PTR gdb_run_tid; /* 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; +UINT_PTR gdb_dbg_pid; +UINT_PTR gdb_dbg_tid; /* PRIVATE FUNCTIONS **********************************************************/ static -HANDLE -hex_to_thread(char* buffer) +UINT_PTR +hex_to_tid(char* buffer) { ULONG_PTR ret = 0; char hex; @@ -32,12 +28,13 @@ hex_to_thread(char* buffer) { hex = hex_value(*buffer++); if (hex < 0) - return (HANDLE)ret; + return ret; ret <<= 4; ret += hex; } - return (HANDLE)ret; + return ret; } +#define hex_to_pid hex_to_tid static ULONG64 @@ -65,26 +62,26 @@ handle_gdb_set_thread(void) { case 'c': if (strcmp(&gdb_input[2], "-1") == 0) - gdb_run_thread = (HANDLE)-1; + gdb_run_tid = (ULONG_PTR)-1; else - gdb_run_thread = hex_to_thread(&gdb_input[2]); + gdb_run_tid = hex_to_tid(&gdb_input[2]); 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; - gdb_dbg_thread = (HANDLE)-1; + gdb_dbg_pid = (UINT_PTR)-1; + gdb_dbg_tid = (UINT_PTR)-1; } else { 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) - gdb_dbg_thread = (HANDLE)-1; + gdb_dbg_tid = (UINT_PTR)-1; else - gdb_dbg_thread = hex_to_thread(ptr); + gdb_dbg_tid = hex_to_tid(ptr); } send_gdb_packet("OK"); break; @@ -112,26 +109,22 @@ static void handle_gdb_thread_alive(void) { - char* ptr = strstr(gdb_input, ".") + 1; - CLIENT_ID ClientId; + ULONG_PTR Pid, Tid; PETHREAD Thread; - NTSTATUS Status; - ClientId.UniqueProcess = hex_to_thread(&gdb_input[2]); - ClientId.UniqueThread = hex_to_thread(ptr); + Pid = hex_to_pid(&gdb_input[2]); + 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 doesn't exist */ - send_gdb_packet("E03"); - return; - } + Thread = find_thread(Pid, Tid); - /* It's OK */ - ObDereferenceObject(Thread); - send_gdb_packet("OK"); + if (Thread != NULL) + send_gdb_packet("OK"); + else + send_gdb_packet("E03"); } /* q* packets */ @@ -165,9 +158,9 @@ handle_gdb_query( if (strcmp(gdb_input, "qC") == 0) { char gdb_out[64]; - sprintf(gdb_out, "QC:p%p.%p;", - PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread), - PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)); + sprintf(gdb_out, "QC:p%"PRIxPTR".%"PRIxPTR";", + handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)), + handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))); send_gdb_packet(gdb_out); return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); } @@ -175,44 +168,35 @@ handle_gdb_query( if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0) || (strncmp(gdb_input, "qsThreadInfo", 12) == 0)) { - LIST_ENTRY* ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer; BOOLEAN FirstThread = TRUE; PEPROCESS Process; PETHREAD Thread; char gdb_out[1024]; - char* ptr; + char* ptr = gdb_out; BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0; - /* Maybe this was not initialized yet */ - if (!ProcessListHead->Flink) + if (Resuming) { - char gdb_out[64]; - - if (Resuming) + if (CurrentProcessEntry == (LIST_ENTRY*)1) { - /* there is only one thread to tell about */ + /* We're done */ send_gdb_packet("l"); + CurrentProcessEntry = NULL; 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) + if ((CurrentProcessEntry == ProcessListHead) || + (CurrentProcessEntry == NULL)) /* Ps is not initialized */ { - /* We're done */ - send_gdb_packet("l"); + /* We're almost done. Tell GDB about the idle thread */ + send_gdb_packet("mp1.1"); + CurrentProcessEntry = (LIST_ENTRY*)1; return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); } @@ -244,7 +228,9 @@ handle_gdb_query( } 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)) { /* send what we got */ @@ -319,11 +305,10 @@ ReadMemorySendHandler( KdpSendPacketHandler = NULL; KdpManipulateStateHandler = NULL; - /* Detach if we have to */ - if (AttachedProcess != NULL) + /* Reset the TLB */ + if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId()) { - KeDetachProcess(); - AttachedProcess = NULL; + __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]); } } @@ -343,17 +328,17 @@ handle_gdb_read_mem( MessageData->Length = 0; *MessageLength = 0; - /* Attach to the debug process to read its memory */ - if (gdb_dbg_process != PsGetCurrentProcessId()) + /* Set the TLB according to the process being read. Pid 0 means any process. */ + if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId()) { - NTSTATUS Status = PsLookupProcessByProcessId(gdb_dbg_process, &AttachedProcess); - if (!NT_SUCCESS(Status)) + PEPROCESS AttachedProcess = find_process(gdb_dbg_pid); + if (AttachedProcess == NULL) { 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); + __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]); } State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]); diff --git a/reactos/drivers/base/kdgdb/gdb_send.c b/reactos/drivers/base/kdgdb/gdb_send.c index 87aeca160c4..dfbc7b6b9df 100644 --- a/reactos/drivers/base/kdgdb/gdb_send.c +++ b/reactos/drivers/base/kdgdb/gdb_send.c @@ -168,15 +168,22 @@ gdb_send_exception(void) { char gdb_out[1024]; char* ptr = gdb_out; - DBGKM_EXCEPTION64* Exception = &CurrentStateChange.u.Exception; + PETHREAD Thread = (PETHREAD)(ULONG_PTR)CurrentStateChange.Thread; /* Report to GDB */ *ptr++ = 'T'; - 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)); + if (CurrentStateChange.NewState == DbgKdExceptionStateChange) + { + EXCEPTION_RECORD64* ExceptionRecord = &CurrentStateChange.u.Exception.ExceptionRecord; + 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); send_gdb_packet(gdb_out); } diff --git a/reactos/drivers/base/kdgdb/i386_sup.c b/reactos/drivers/base/kdgdb/i386_sup.c index dc752b531d8..7cab7fef51b 100644 --- a/reactos/drivers/base/kdgdb/i386_sup.c +++ b/reactos/drivers/base/kdgdb/i386_sup.c @@ -7,8 +7,6 @@ #include "kdgdb.h" -#include - enum reg_name { EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, @@ -85,36 +83,62 @@ 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) + /* See if the guy got a stack */ + if (Thread->Tcb.InitialStack == 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) + { + PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame; - *size = 4; - switch (reg_name) + *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); + } + } + else { - 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); + /* 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; } @@ -132,7 +156,10 @@ gdb_send_registers( unsigned short size; 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++) { @@ -150,10 +177,10 @@ gdb_send_registers( else { PETHREAD DbgThread; - NTSTATUS Status; - Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread); - if (!NT_SUCCESS(Status)) + DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid); + + if (DbgThread == NULL) { /* Thread is dead */ send_gdb_packet("E03"); @@ -199,7 +226,8 @@ gdb_send_register( /* Get the GDB register name (gdb_input = "pXX") */ 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 */ ptr = ctx_to_reg(&CurrentContext, reg_name, &size); @@ -207,10 +235,10 @@ gdb_send_register( else { PETHREAD DbgThread; - NTSTATUS Status; - Status = PsLookupThreadByThreadId(gdb_dbg_thread, &DbgThread); - if (!NT_SUCCESS(Status)) + DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid); + + if (DbgThread == NULL) { /* Thread is dead */ send_gdb_packet("E03"); diff --git a/reactos/drivers/base/kdgdb/kdgdb.h b/reactos/drivers/base/kdgdb/kdgdb.h index 71f788dcebd..24838e7a8a7 100644 --- a/reactos/drivers/base/kdgdb/kdgdb.h +++ b/reactos/drivers/base/kdgdb/kdgdb.h @@ -13,9 +13,12 @@ #include #include #include +#include #include #include +#include + #define KDDEBUG /* uncomment to enable debugging this dll */ #ifndef KDDEBUG @@ -25,6 +28,18 @@ extern ULONG KdpDbgPrint(const char* Format, ...); #define KDDBGPRINT KdpDbgPrint #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 VOID InitManipulateFromStateChange( @@ -51,8 +66,8 @@ typedef KDSTATUS (*KDP_MANIPULATESTATE_HANDLER)( ); /* gdb_input.c */ -extern HANDLE gdb_dbg_thread; -extern HANDLE gdb_dbg_process; +extern UINT_PTR gdb_dbg_tid; +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_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 DBGKD_GET_VERSION64 KdVersion; extern KDDEBUGGER_DATA64* KdDebuggerDataBlock; +extern LIST_ENTRY* ProcessListHead; 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); +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 */ extern KDSTATUS gdb_send_register(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext); diff --git a/reactos/drivers/base/kdgdb/kdpacket.c b/reactos/drivers/base/kdgdb/kdpacket.c index 238c4db23fc..4376d4ebdeb 100644 --- a/reactos/drivers/base/kdgdb/kdpacket.c +++ b/reactos/drivers/base/kdgdb/kdpacket.c @@ -14,18 +14,20 @@ FirstSendHandler( _In_ ULONG PacketType, _In_ PSTRING MessageHeader, _In_ PSTRING MessageData); -static BOOLEAN CanSendData = FALSE; +static BOOLEAN InException = FALSE; /* GLOBALS ********************************************************************/ DBGKD_GET_VERSION64 KdVersion; KDDEBUGGER_DATA64* KdDebuggerDataBlock; -BOOLEAN InException = FALSE; +LIST_ENTRY* ProcessListHead; /* Callbacks used to communicate with KD aside from GDB */ KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler; KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL; /* Data describing the current exception */ DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange; CONTEXT CurrentContext; +PEPROCESS TheIdleProcess; +PETHREAD TheIdleThread; /* PRIVATE FUNCTIONS **********************************************************/ @@ -130,6 +132,8 @@ static void send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange) { + InException = TRUE; + switch (StateChange->NewState) { case DbgKdLoadSymbolsStateChange: @@ -139,17 +143,22 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange) break; } case DbgKdExceptionStateChange: + { + PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread; /* 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)(ULONG_PTR)StateChange->Thread); - gdb_dbg_process = PsGetThreadProcessId((PETHREAD)(ULONG_PTR)StateChange->Thread); + KDDBGPRINT("Exception 0x%08x in thread p%p.%p.\n", + StateChange->u.Exception.ExceptionRecord.ExceptionCode, + 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(); /* 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 */ while (1); @@ -162,7 +171,7 @@ send_kd_debug_io( _In_ DBGKD_DEBUG_IO* DebugIO, _In_ PSTRING String) { - if (!CanSendData) + if (InException) return; switch (DebugIO->ApiNumber) @@ -217,6 +226,9 @@ ContinueManipulateStateHandler( /* We definitely are at the end of the send <-> receive loop, if any */ KdpSendPacketHandler = NULL; KdpManipulateStateHandler = NULL; + /* We're not handling an exception anymore */ + InException = FALSE; + return KdPacketReceived; } @@ -244,10 +256,11 @@ GetVersionSendHandler( RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion)); DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList; 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; - KdpManipulateStateHandler = ContinueManipulateStateHandler; + KdpManipulateStateHandler = GetContextManipulateHandler; } static @@ -267,9 +280,6 @@ GetVersionManipulateStateHandler( KdpSendPacketHandler = GetVersionSendHandler; KdpManipulateStateHandler = NULL; - /* This will make KD breakin and we will be able to properly attach to GDB */ - KdContext->KdpControlCPending = TRUE; - return KdPacketReceived; } @@ -281,6 +291,7 @@ FirstSendHandler( _In_ PSTRING MessageData) { DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer; + PETHREAD Thread; if (PacketType == PACKET_TYPE_KD_DEBUG_IO) { @@ -296,7 +307,19 @@ FirstSendHandler( while(1); } + KDDBGPRINT("KDGDB: START!\n"); + + Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread; + + /* Set up the current state */ 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 */ KdpSendPacketHandler = NULL; diff --git a/reactos/drivers/base/kdgdb/utils.c b/reactos/drivers/base/kdgdb/utils.c new file mode 100644 index 00000000000..01dea3d7f33 --- /dev/null +++ b/reactos/drivers/base/kdgdb/utils.c @@ -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; +}