mirror of
https://github.com/reactos/reactos.git
synced 2025-06-12 14:28:29 +00:00
[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
This commit is contained in:
parent
000f227784
commit
de914f2aed
7 changed files with 263 additions and 126 deletions
|
@ -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...
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
71
reactos/drivers/base/kdgdb/utils.c
Normal file
71
reactos/drivers/base/kdgdb/utils.c
Normal 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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue