mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 03:12:59 +00:00
[KDGDB]
- Better report kernel stack (real back traces for all threads!) - Support reporting loaded libraries (== drivers, hal, etc.). You can even debug KDGDB inside KDGDB :-) - A few improvements here and there CORE-8531 svn path=/trunk/; revision=72533
This commit is contained in:
parent
24834c0492
commit
9598f87c7c
5 changed files with 394 additions and 288 deletions
|
@ -20,6 +20,13 @@ static struct
|
||||||
UINT_PTR gdb_dbg_pid;
|
UINT_PTR gdb_dbg_pid;
|
||||||
UINT_PTR gdb_dbg_tid;
|
UINT_PTR gdb_dbg_tid;
|
||||||
|
|
||||||
|
static inline
|
||||||
|
KDSTATUS
|
||||||
|
LOOP_IF_SUCCESS(x)
|
||||||
|
{
|
||||||
|
return (x == KdPacketReceived) ? (KDSTATUS)-1 : x;
|
||||||
|
}
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
static
|
static
|
||||||
UINT_PTR
|
UINT_PTR
|
||||||
|
@ -58,9 +65,11 @@ hex_to_address(char* buffer)
|
||||||
|
|
||||||
/* H* packets */
|
/* H* packets */
|
||||||
static
|
static
|
||||||
void
|
KDSTATUS
|
||||||
handle_gdb_set_thread(void)
|
handle_gdb_set_thread(void)
|
||||||
{
|
{
|
||||||
|
KDSTATUS Status;
|
||||||
|
|
||||||
switch (gdb_input[1])
|
switch (gdb_input[1])
|
||||||
{
|
{
|
||||||
case 'c':
|
case 'c':
|
||||||
|
@ -68,7 +77,7 @@ handle_gdb_set_thread(void)
|
||||||
gdb_run_tid = (ULONG_PTR)-1;
|
gdb_run_tid = (ULONG_PTR)-1;
|
||||||
else
|
else
|
||||||
gdb_run_tid = hex_to_tid(&gdb_input[2]);
|
gdb_run_tid = hex_to_tid(&gdb_input[2]);
|
||||||
send_gdb_packet("OK");
|
Status = 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);
|
||||||
|
@ -98,20 +107,23 @@ handle_gdb_set_thread(void)
|
||||||
gdb_dbg_tid = hex_to_tid(ptr);
|
gdb_dbg_tid = hex_to_tid(ptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
send_gdb_packet("OK");
|
Status = send_gdb_packet("OK");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input);
|
KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input);
|
||||||
send_gdb_packet("");
|
Status = send_gdb_packet("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
KDSTATUS
|
||||||
handle_gdb_thread_alive(void)
|
handle_gdb_thread_alive(void)
|
||||||
{
|
{
|
||||||
ULONG_PTR Pid, Tid;
|
ULONG_PTR Pid, Tid;
|
||||||
PETHREAD Thread;
|
PETHREAD Thread;
|
||||||
|
KDSTATUS Status;
|
||||||
|
|
||||||
#if MONOPROCESS
|
#if MONOPROCESS
|
||||||
Pid = 0;
|
Pid = 0;
|
||||||
|
@ -131,45 +143,44 @@ handle_gdb_thread_alive(void)
|
||||||
Thread = find_thread(Pid, Tid);
|
Thread = find_thread(Pid, Tid);
|
||||||
|
|
||||||
if (Thread != NULL)
|
if (Thread != NULL)
|
||||||
send_gdb_packet("OK");
|
Status = send_gdb_packet("OK");
|
||||||
else
|
else
|
||||||
send_gdb_packet("E03");
|
Status = send_gdb_packet("E03");
|
||||||
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* q* packets */
|
/* q* packets */
|
||||||
static
|
static
|
||||||
void
|
KDSTATUS
|
||||||
handle_gdb_query(void)
|
handle_gdb_query(void)
|
||||||
{
|
{
|
||||||
if (strncmp(gdb_input, "qSupported:", 11) == 0)
|
if (strncmp(gdb_input, "qSupported:", 11) == 0)
|
||||||
{
|
{
|
||||||
#if MONOPROCESS
|
#if MONOPROCESS
|
||||||
send_gdb_packet("PacketSize=1000;");
|
return send_gdb_packet("PacketSize=1000;qXfer:libraries:read+;");
|
||||||
#else
|
#else
|
||||||
send_gdb_packet("PacketSize=1000;multiprocess+;");
|
return send_gdb_packet("PacketSize=1000;multiprocess+;qXfer:libraries:read+;");
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(gdb_input, "qAttached", 9) == 0)
|
if (strncmp(gdb_input, "qAttached", 9) == 0)
|
||||||
{
|
{
|
||||||
#if MONOPROCESS
|
#if MONOPROCESS
|
||||||
send_gdb_packet("1");
|
return send_gdb_packet("1");
|
||||||
#else
|
#else
|
||||||
UINT_PTR queried_pid = hex_to_pid(&gdb_input[10]);
|
UINT_PTR queried_pid = hex_to_pid(&gdb_input[10]);
|
||||||
/* Let's say we created system process */
|
/* Let's say we created system process */
|
||||||
if (gdb_pid_to_handle(queried_pid) == NULL)
|
if (gdb_pid_to_handle(queried_pid) == NULL)
|
||||||
send_gdb_packet("0");
|
return send_gdb_packet("0");
|
||||||
else
|
else
|
||||||
send_gdb_packet("1");
|
return send_gdb_packet("1");
|
||||||
#endif
|
#endif
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(gdb_input, "qRcmd,", 6) == 0)
|
if (strncmp(gdb_input, "qRcmd,", 6) == 0)
|
||||||
{
|
{
|
||||||
send_gdb_packet("OK");
|
return send_gdb_packet("OK");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(gdb_input, "qC") == 0)
|
if (strcmp(gdb_input, "qC") == 0)
|
||||||
|
@ -183,112 +194,69 @@ handle_gdb_query(void)
|
||||||
handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)),
|
handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)),
|
||||||
handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
|
handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
|
||||||
#endif
|
#endif
|
||||||
send_gdb_packet(gdb_out);
|
return send_gdb_packet(gdb_out);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0)
|
if (strncmp(gdb_input, "qfThreadInfo", 12) == 0)
|
||||||
|| (strncmp(gdb_input, "qsThreadInfo", 12) == 0))
|
|
||||||
{
|
{
|
||||||
BOOLEAN FirstThread = TRUE;
|
|
||||||
PEPROCESS Process;
|
PEPROCESS Process;
|
||||||
PETHREAD Thread;
|
char gdb_out[40];
|
||||||
char gdb_out[1024];
|
LIST_ENTRY* CurrentProcessEntry;
|
||||||
char* ptr = gdb_out;
|
|
||||||
BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0;
|
|
||||||
/* Keep track of where we are. */
|
|
||||||
static LIST_ENTRY* CurrentProcessEntry;
|
|
||||||
static LIST_ENTRY* CurrentThreadEntry;
|
|
||||||
|
|
||||||
ptr = gdb_out;
|
|
||||||
|
|
||||||
*ptr++ = 'm';
|
|
||||||
/* NULL terminate in case we got nothing more to iterate */
|
|
||||||
*ptr = '\0';
|
|
||||||
|
|
||||||
if (!Resuming)
|
|
||||||
{
|
|
||||||
/* Report the idle thread */
|
|
||||||
#if MONOPROCESS
|
|
||||||
ptr += sprintf(ptr, "1");
|
|
||||||
#else
|
|
||||||
ptr += sprintf(gdb, "p1.1");
|
|
||||||
#endif
|
|
||||||
/* Initialize the entries */
|
|
||||||
CurrentProcessEntry = ProcessListHead->Flink;
|
CurrentProcessEntry = ProcessListHead->Flink;
|
||||||
CurrentThreadEntry = NULL;
|
|
||||||
FirstThread = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CurrentProcessEntry == NULL) /* Ps is not initialized */
|
if (CurrentProcessEntry == NULL) /* Ps is not initialized */
|
||||||
{
|
{
|
||||||
send_gdb_packet(Resuming ? "l" : gdb_out);
|
#if MONOPROCESS
|
||||||
return;
|
return send_gdb_packet("m1");
|
||||||
|
#else
|
||||||
|
return send_gdb_packet("mp1.1");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We will push threads as we find them */
|
||||||
|
start_gdb_packet();
|
||||||
|
|
||||||
|
/* Start with the system thread */
|
||||||
|
#if MONOPROCESS
|
||||||
|
send_gdb_partial_packet("m1");
|
||||||
|
#else
|
||||||
|
send_gdb_partial_packet("mp1.1");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* List all the processes */
|
/* List all the processes */
|
||||||
for ( ;
|
for ( ;
|
||||||
CurrentProcessEntry != ProcessListHead;
|
CurrentProcessEntry != ProcessListHead;
|
||||||
CurrentProcessEntry = CurrentProcessEntry->Flink)
|
CurrentProcessEntry = CurrentProcessEntry->Flink)
|
||||||
{
|
{
|
||||||
|
LIST_ENTRY* CurrentThreadEntry;
|
||||||
|
|
||||||
Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
|
Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
|
||||||
|
|
||||||
if (CurrentThreadEntry != NULL)
|
|
||||||
CurrentThreadEntry = CurrentThreadEntry->Flink;
|
|
||||||
else
|
|
||||||
CurrentThreadEntry = Process->ThreadListHead.Flink;
|
|
||||||
|
|
||||||
/* List threads from this process */
|
/* List threads from this process */
|
||||||
for ( ;
|
for ( CurrentThreadEntry = Process->ThreadListHead.Flink;
|
||||||
CurrentThreadEntry != &Process->ThreadListHead;
|
CurrentThreadEntry != &Process->ThreadListHead;
|
||||||
CurrentThreadEntry = CurrentThreadEntry->Flink)
|
CurrentThreadEntry = CurrentThreadEntry->Flink)
|
||||||
{
|
{
|
||||||
Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry);
|
PETHREAD Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry);
|
||||||
|
|
||||||
/* See if we should add a comma */
|
|
||||||
if (FirstThread)
|
|
||||||
{
|
|
||||||
FirstThread = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*ptr++ = ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MONOPROCESS
|
#if MONOPROCESS
|
||||||
ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
|
_snprintf(gdb_out, 40, ",%p", handle_to_gdb_tid(Thread->Cid.UniqueThread));
|
||||||
"%p",
|
|
||||||
handle_to_gdb_tid(Thread->Cid.UniqueThread));
|
|
||||||
#else
|
#else
|
||||||
ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
|
_snprintf(gdb_out, 40, ",p%p.%p",
|
||||||
"p%p.%p",
|
|
||||||
handle_to_gdb_pid(Process->UniqueProcessId),
|
handle_to_gdb_pid(Process->UniqueProcessId),
|
||||||
handle_to_gdb_tid(Thread->Cid.UniqueThread));
|
handle_to_gdb_tid(Thread->Cid.UniqueThread));
|
||||||
#endif
|
#endif
|
||||||
if (ptr > (gdb_out + 1024))
|
send_gdb_partial_packet(gdb_out);
|
||||||
{
|
|
||||||
/* send what we got */
|
|
||||||
send_gdb_packet(gdb_out);
|
|
||||||
/* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* We're done for this process */
|
|
||||||
CurrentThreadEntry = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gdb_out[1] == '\0')
|
return finish_gdb_packet();
|
||||||
{
|
|
||||||
/* We didn't iterate over anything, meaning we were already done */
|
|
||||||
send_gdb_packet("l");
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (strncmp(gdb_input, "qsThreadInfo", 12) == 0)
|
||||||
{
|
{
|
||||||
send_gdb_packet(gdb_out);
|
/* We sent the whole thread list on first qfThreadInfo call */
|
||||||
}
|
return send_gdb_packet("l");
|
||||||
/* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(gdb_input, "qThreadExtraInfo,", 17) == 0)
|
if (strncmp(gdb_input, "qThreadExtraInfo,", 17) == 0)
|
||||||
|
@ -330,27 +298,117 @@ handle_gdb_query(void)
|
||||||
String.Length = sprintf(out_string, "%.*s", 16, Process->ImageFileName);
|
String.Length = sprintf(out_string, "%.*s", 16, Process->ImageFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
gdb_send_debug_io(&String, FALSE);
|
return gdb_send_debug_io(&String, FALSE);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(gdb_input, "qOffsets", 8) == 0)
|
if (strncmp(gdb_input, "qOffsets", 8) == 0)
|
||||||
{
|
{
|
||||||
/* We load ntoskrnl at 0x80800000 while compiling it at 0x00800000 base adress */
|
/* We load ntoskrnl at 0x80800000 while compiling it at 0x00800000 base adress */
|
||||||
send_gdb_packet("TextSeg=80000000");
|
return send_gdb_packet("TextSeg=80000000");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(gdb_input, "qTStatus") == 0)
|
if (strcmp(gdb_input, "qTStatus") == 0)
|
||||||
{
|
{
|
||||||
/* No tracepoint support */
|
/* No tracepoint support */
|
||||||
send_gdb_packet("T0");
|
return send_gdb_packet("T0");
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
if (strcmp(gdb_input, "qSymbol::") == 0)
|
||||||
|
{
|
||||||
|
/* No need */
|
||||||
|
return send_gdb_packet("OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(gdb_input, "qXfer:libraries:read::", 22) == 0)
|
||||||
|
{
|
||||||
|
static LIST_ENTRY* CurrentEntry = NULL;
|
||||||
|
char str_helper[256];
|
||||||
|
char name_helper[64];
|
||||||
|
ULONG_PTR Offset = hex_to_address(&gdb_input[22]);
|
||||||
|
ULONG_PTR ToSend = hex_to_address(strstr(&gdb_input[22], ",") + 1);
|
||||||
|
ULONG Sent = 0;
|
||||||
|
static BOOLEAN allDone = FALSE;
|
||||||
|
|
||||||
|
KDDBGPRINT("KDGDB: qXfer:libraries:read !\n");
|
||||||
|
|
||||||
|
/* Start the packet */
|
||||||
|
start_gdb_packet();
|
||||||
|
|
||||||
|
if (allDone)
|
||||||
|
{
|
||||||
|
send_gdb_partial_packet("l");
|
||||||
|
allDone = FALSE;
|
||||||
|
return finish_gdb_packet();
|
||||||
|
}
|
||||||
|
|
||||||
|
send_gdb_partial_packet("m");
|
||||||
|
Sent++;
|
||||||
|
|
||||||
|
/* Are we starting ? */
|
||||||
|
if (Offset == 0)
|
||||||
|
{
|
||||||
|
Sent += send_gdb_partial_binary("<?xml version=\"1.0\"?>", 21);
|
||||||
|
Sent += send_gdb_partial_binary("<library-list>", 14);
|
||||||
|
|
||||||
|
CurrentEntry = ModuleListHead->Flink;
|
||||||
|
|
||||||
|
if (!CurrentEntry)
|
||||||
|
{
|
||||||
|
/* Ps is not initialized. Send end of XML data or mark that we are finished. */
|
||||||
|
Sent += send_gdb_partial_binary("</library-list>", 15);
|
||||||
|
allDone = TRUE;
|
||||||
|
return finish_gdb_packet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ;
|
||||||
|
CurrentEntry != ModuleListHead;
|
||||||
|
CurrentEntry = CurrentEntry->Flink)
|
||||||
|
{
|
||||||
|
PLDR_DATA_TABLE_ENTRY TableEntry = CONTAINING_RECORD(CurrentEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
|
||||||
|
PVOID DllBase = (PVOID)((ULONG_PTR)TableEntry->DllBase + 0x1000);
|
||||||
|
LONG mem_length;
|
||||||
|
char* ptr;
|
||||||
|
|
||||||
|
/* Convert names to lower case. Yes this _is_ ugly */
|
||||||
|
_snprintf(name_helper, 64, "%wZ", &TableEntry->BaseDllName);
|
||||||
|
for (ptr = name_helper; *ptr; ptr++)
|
||||||
|
{
|
||||||
|
if (*ptr >= 'A' && *ptr <= 'Z')
|
||||||
|
*ptr += 'a' - 'A';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GDB doesn't load the file if you don't prefix it with a drive letter... */
|
||||||
|
mem_length = _snprintf(str_helper, 256, "<library name=\"C:\\%s\"><segment address=\"0x%p\"/></library>", &name_helper, DllBase);
|
||||||
|
|
||||||
|
/* DLL name must be too long. */
|
||||||
|
if (mem_length < 0)
|
||||||
|
{
|
||||||
|
KDDBGPRINT("Failed to report %wZ\n", &TableEntry->BaseDllName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Sent + mem_length) > ToSend)
|
||||||
|
{
|
||||||
|
/* We're done for this pass */
|
||||||
|
return finish_gdb_packet();
|
||||||
|
}
|
||||||
|
|
||||||
|
Sent += send_gdb_partial_binary(str_helper, mem_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ToSend - Sent) > 15)
|
||||||
|
{
|
||||||
|
Sent += send_gdb_partial_binary("</library-list>", 15);
|
||||||
|
allDone = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return finish_gdb_packet();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
|
KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
|
||||||
send_gdb_packet("");
|
return send_gdb_packet("");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -413,6 +471,8 @@ ReadMemorySendHandler(
|
||||||
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
|
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
/* Only do this if Ps is initialized */
|
||||||
|
if (ProcessListHead->Flink)
|
||||||
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
|
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,16 +502,14 @@ handle_gdb_read_mem(
|
||||||
if (AttachedThread == NULL)
|
if (AttachedThread == NULL)
|
||||||
{
|
{
|
||||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||||
send_gdb_packet("E03");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachedProcess = AttachedThread->Tcb.Process;
|
AttachedProcess = AttachedThread->Tcb.Process;
|
||||||
if (AttachedProcess == NULL)
|
if (AttachedProcess == NULL)
|
||||||
{
|
{
|
||||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||||
send_gdb_packet("E03");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
__writecr3(AttachedProcess->DirectoryTableBase[0]);
|
__writecr3(AttachedProcess->DirectoryTableBase[0]);
|
||||||
}
|
}
|
||||||
|
@ -462,9 +520,10 @@ handle_gdb_read_mem(
|
||||||
if (AttachedProcess == NULL)
|
if (AttachedProcess == NULL)
|
||||||
{
|
{
|
||||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||||
send_gdb_packet("E03");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
/* Only do this if Ps is initialized */
|
||||||
|
if (ProcessListHead->Flink)
|
||||||
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
|
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -474,7 +533,6 @@ handle_gdb_read_mem(
|
||||||
|
|
||||||
/* KD will reply with KdSendPacket. Catch it */
|
/* KD will reply with KdSendPacket. Catch it */
|
||||||
KdpSendPacketHandler = ReadMemorySendHandler;
|
KdpSendPacketHandler = ReadMemorySendHandler;
|
||||||
|
|
||||||
return KdPacketReceived;
|
return KdPacketReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,6 +572,8 @@ WriteMemorySendHandler(
|
||||||
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
|
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
/* Only do this if Ps is initialized */
|
||||||
|
if (ProcessListHead->Flink)
|
||||||
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
|
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -546,16 +606,14 @@ handle_gdb_write_mem(
|
||||||
if (AttachedThread == NULL)
|
if (AttachedThread == NULL)
|
||||||
{
|
{
|
||||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||||
send_gdb_packet("E03");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachedProcess = AttachedThread->Tcb.Process;
|
AttachedProcess = AttachedThread->Tcb.Process;
|
||||||
if (AttachedProcess == NULL)
|
if (AttachedProcess == NULL)
|
||||||
{
|
{
|
||||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||||
send_gdb_packet("E03");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
__writecr3(AttachedProcess->DirectoryTableBase[0]);
|
__writecr3(AttachedProcess->DirectoryTableBase[0]);
|
||||||
}
|
}
|
||||||
|
@ -566,9 +624,10 @@ handle_gdb_write_mem(
|
||||||
if (AttachedProcess == NULL)
|
if (AttachedProcess == NULL)
|
||||||
{
|
{
|
||||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||||
send_gdb_packet("E03");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
/* Only do this if Ps is initialized */
|
||||||
|
if (ProcessListHead->Flink)
|
||||||
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
|
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -578,8 +637,7 @@ handle_gdb_write_mem(
|
||||||
if (BufferLength == 0)
|
if (BufferLength == 0)
|
||||||
{
|
{
|
||||||
/* Nothing to do */
|
/* Nothing to do */
|
||||||
send_gdb_packet("OK");
|
return LOOP_IF_SUCCESS(send_gdb_packet("OK"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
State->u.WriteMemory.TransferCount = BufferLength;
|
State->u.WriteMemory.TransferCount = BufferLength;
|
||||||
|
@ -613,7 +671,6 @@ handle_gdb_write_mem(
|
||||||
|
|
||||||
/* KD will reply with KdSendPacket. Catch it */
|
/* KD will reply with KdSendPacket. Catch it */
|
||||||
KdpSendPacketHandler = WriteMemorySendHandler;
|
KdpSendPacketHandler = WriteMemorySendHandler;
|
||||||
|
|
||||||
return KdPacketReceived;
|
return KdPacketReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,8 +755,7 @@ handle_gdb_insert_breakpoint(
|
||||||
{
|
{
|
||||||
/* We don't have a way to keep track of this break point. Fail. */
|
/* We don't have a way to keep track of this break point. Fail. */
|
||||||
KDDBGPRINT("No breakpoint slot available!\n");
|
KDDBGPRINT("No breakpoint slot available!\n");
|
||||||
send_gdb_packet("E01");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
State->ApiNumber = DbgKdWriteBreakPointApi;
|
State->ApiNumber = DbgKdWriteBreakPointApi;
|
||||||
|
@ -713,8 +769,7 @@ handle_gdb_insert_breakpoint(
|
||||||
}
|
}
|
||||||
|
|
||||||
KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
|
KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
|
||||||
send_gdb_packet("E01");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -793,8 +848,7 @@ handle_gdb_remove_breakpoint(
|
||||||
if (Handle == 0)
|
if (Handle == 0)
|
||||||
{
|
{
|
||||||
KDDBGPRINT("Received %s, but breakpoint was never inserted ?!\n", gdb_input);
|
KDDBGPRINT("Received %s, but breakpoint was never inserted ?!\n", gdb_input);
|
||||||
send_gdb_packet("E01");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
State->ApiNumber = DbgKdRestoreBreakPointApi;
|
State->ApiNumber = DbgKdRestoreBreakPointApi;
|
||||||
|
@ -808,8 +862,7 @@ handle_gdb_remove_breakpoint(
|
||||||
}
|
}
|
||||||
|
|
||||||
KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
|
KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
|
||||||
send_gdb_packet("E01");
|
return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -820,8 +873,13 @@ handle_gdb_c(
|
||||||
_Out_ PULONG MessageLength,
|
_Out_ PULONG MessageLength,
|
||||||
_Inout_ PKD_CONTEXT KdContext)
|
_Inout_ PKD_CONTEXT KdContext)
|
||||||
{
|
{
|
||||||
|
KDSTATUS Status;
|
||||||
|
|
||||||
/* Tell GDB everything is fine, we will handle it */
|
/* Tell GDB everything is fine, we will handle it */
|
||||||
send_gdb_packet("OK");
|
Status = send_gdb_packet("OK");
|
||||||
|
if (Status != KdPacketReceived)
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
|
||||||
if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
|
if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
|
||||||
{
|
{
|
||||||
|
@ -873,8 +931,7 @@ handle_gdb_v(
|
||||||
if (gdb_input[5] == '?')
|
if (gdb_input[5] == '?')
|
||||||
{
|
{
|
||||||
/* Report what we support */
|
/* Report what we support */
|
||||||
send_gdb_packet("vCont;c;s");
|
return LOOP_IF_SUCCESS(send_gdb_packet("vCont;c;s"));
|
||||||
return (KDSTATUS)-1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(gdb_input, "vCont;c", 7) == 0)
|
if (strncmp(gdb_input, "vCont;c", 7) == 0)
|
||||||
|
@ -890,7 +947,7 @@ handle_gdb_v(
|
||||||
}
|
}
|
||||||
|
|
||||||
KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
|
KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
|
||||||
return KdPacketReceived;
|
return LOOP_IF_SUCCESS(send_gdb_packet(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
KDSTATUS
|
KDSTATUS
|
||||||
|
@ -904,8 +961,9 @@ gdb_receive_and_interpret_packet(
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
KDDBGPRINT("KDGBD: Receiving packet.\n");
|
||||||
Status = gdb_receive_packet(KdContext);
|
Status = gdb_receive_packet(KdContext);
|
||||||
KDDBGPRINT("KDGBD: Packet received with status %u\n", Status);
|
KDDBGPRINT("KDGBD: Packet \"%s\" received with status %u\n", gdb_input, Status);
|
||||||
|
|
||||||
if (Status != KdPacketReceived)
|
if (Status != KdPacketReceived)
|
||||||
return Status;
|
return Status;
|
||||||
|
@ -916,34 +974,34 @@ gdb_receive_and_interpret_packet(
|
||||||
{
|
{
|
||||||
case '?':
|
case '?':
|
||||||
/* Send the Status */
|
/* Send the Status */
|
||||||
gdb_send_exception();
|
Status = LOOP_IF_SUCCESS(gdb_send_exception());
|
||||||
break;
|
break;
|
||||||
case '!':
|
case '!':
|
||||||
send_gdb_packet("OK");
|
Status = LOOP_IF_SUCCESS(send_gdb_packet("OK"));
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
Status = handle_gdb_c(State, MessageData, MessageLength, KdContext);
|
Status = handle_gdb_c(State, MessageData, MessageLength, KdContext);
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
gdb_send_registers();
|
Status = LOOP_IF_SUCCESS(gdb_send_registers());
|
||||||
break;
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
handle_gdb_set_thread();
|
Status = LOOP_IF_SUCCESS(handle_gdb_set_thread());
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
|
Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
gdb_send_register();
|
Status = LOOP_IF_SUCCESS(gdb_send_register());
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
handle_gdb_query();
|
Status = LOOP_IF_SUCCESS(handle_gdb_query());
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
Status = handle_gdb_s(State, MessageData, MessageLength, KdContext);
|
Status = handle_gdb_s(State, MessageData, MessageLength, KdContext);
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
handle_gdb_thread_alive();
|
Status = LOOP_IF_SUCCESS(handle_gdb_thread_alive());
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
|
Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
|
||||||
|
@ -960,7 +1018,7 @@ gdb_receive_and_interpret_packet(
|
||||||
default:
|
default:
|
||||||
/* We don't know how to handle this request. */
|
/* We don't know how to handle this request. */
|
||||||
KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
|
KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
|
||||||
send_gdb_packet("");
|
Status = LOOP_IF_SUCCESS(send_gdb_packet(""));
|
||||||
}
|
}
|
||||||
} while (Status == (KDSTATUS)-1);
|
} while (Status == (KDSTATUS)-1);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
/* LOCALS *********************************************************************/
|
/* LOCALS *********************************************************************/
|
||||||
const char hex_chars[] = "0123456789abcdef";
|
const char hex_chars[] = "0123456789abcdef";
|
||||||
|
static CHAR currentChecksum = 0;
|
||||||
|
|
||||||
/* PRIVATE FUNCTIONS **********************************************************/
|
/* PRIVATE FUNCTIONS **********************************************************/
|
||||||
static
|
static
|
||||||
|
@ -48,126 +49,151 @@ exception_code_to_gdb(NTSTATUS code, char* out)
|
||||||
|
|
||||||
/* GLOBAL FUNCTIONS ***********************************************************/
|
/* GLOBAL FUNCTIONS ***********************************************************/
|
||||||
void
|
void
|
||||||
send_gdb_packet(_In_ CHAR* Buffer)
|
start_gdb_packet(void)
|
||||||
{
|
{
|
||||||
UCHAR ack;
|
/* Start the start byte and begin checksum calculation */
|
||||||
|
|
||||||
do {
|
|
||||||
CHAR* ptr = Buffer;
|
|
||||||
CHAR check_sum = 0;
|
|
||||||
|
|
||||||
KdpSendByte('$');
|
KdpSendByte('$');
|
||||||
|
currentChecksum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate checksum */
|
void
|
||||||
check_sum = 0;
|
send_gdb_partial_packet(_In_ const CHAR* Buffer)
|
||||||
|
{
|
||||||
|
const CHAR* ptr = Buffer;
|
||||||
|
|
||||||
|
/* Update check sum and send */
|
||||||
while (*ptr)
|
while (*ptr)
|
||||||
{
|
{
|
||||||
check_sum += *ptr;
|
currentChecksum += *ptr;
|
||||||
KdpSendByte(*ptr++);
|
KdpSendByte(*ptr++);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* append it */
|
|
||||||
KdpSendByte('#');
|
|
||||||
KdpSendByte(hex_chars[(check_sum >> 4) & 0xf]);
|
|
||||||
KdpSendByte(hex_chars[check_sum & 0xf]);
|
|
||||||
|
|
||||||
/* Wait for acknowledgement */
|
|
||||||
if (KdpReceiveByte(&ack) != KdPacketReceived)
|
|
||||||
{
|
|
||||||
KD_DEBUGGER_NOT_PRESENT = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (ack != '+');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
send_gdb_memory(
|
KDSTATUS
|
||||||
_In_ VOID* Buffer,
|
finish_gdb_packet(void)
|
||||||
_In_ size_t Length)
|
|
||||||
{
|
{
|
||||||
UCHAR ack;
|
UCHAR ack;
|
||||||
|
KDSTATUS Status;
|
||||||
|
|
||||||
do {
|
/* Send finish byte and append checksum */
|
||||||
CHAR* ptr = Buffer;
|
|
||||||
CHAR check_sum = 0;
|
|
||||||
size_t len = Length;
|
|
||||||
CHAR Byte;
|
|
||||||
|
|
||||||
KdpSendByte('$');
|
|
||||||
|
|
||||||
/* Send the data */
|
|
||||||
check_sum = 0;
|
|
||||||
while (len--)
|
|
||||||
{
|
|
||||||
Byte = hex_chars[(*ptr >> 4) & 0xf];
|
|
||||||
KdpSendByte(Byte);
|
|
||||||
check_sum += Byte;
|
|
||||||
Byte = hex_chars[*ptr++ & 0xf];
|
|
||||||
KdpSendByte(Byte);
|
|
||||||
check_sum += Byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* append check sum */
|
|
||||||
KdpSendByte('#');
|
KdpSendByte('#');
|
||||||
KdpSendByte(hex_chars[(check_sum >> 4) & 0xf]);
|
KdpSendByte(hex_chars[(currentChecksum >> 4) & 0xf]);
|
||||||
KdpSendByte(hex_chars[check_sum & 0xf]);
|
KdpSendByte(hex_chars[currentChecksum & 0xf]);
|
||||||
|
|
||||||
/* Wait for acknowledgement */
|
/* Wait for acknowledgement */
|
||||||
if (KdpReceiveByte(&ack) != KdPacketReceived)
|
Status = KdpReceiveByte(&ack);
|
||||||
|
|
||||||
|
if (Status != KdPacketReceived)
|
||||||
{
|
{
|
||||||
KD_DEBUGGER_NOT_PRESENT = TRUE;
|
KD_DEBUGGER_NOT_PRESENT = TRUE;
|
||||||
break;
|
return Status;
|
||||||
}
|
}
|
||||||
} while (ack != '+');
|
|
||||||
|
if (ack != '+')
|
||||||
|
return KdPacketNeedsResend;
|
||||||
|
|
||||||
|
return KdPacketReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
KDSTATUS
|
||||||
|
send_gdb_packet(_In_ const CHAR* Buffer)
|
||||||
|
{
|
||||||
|
start_gdb_packet();
|
||||||
|
send_gdb_partial_packet(Buffer);
|
||||||
|
return finish_gdb_packet();
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG
|
||||||
|
send_gdb_partial_binary(
|
||||||
|
_In_ const VOID* Buffer,
|
||||||
|
_In_ size_t Length)
|
||||||
|
{
|
||||||
|
const UCHAR* ptr = Buffer;
|
||||||
|
ULONG Sent = Length;
|
||||||
|
|
||||||
|
while(Length--)
|
||||||
|
{
|
||||||
|
UCHAR Byte = *ptr++;
|
||||||
|
|
||||||
|
switch (Byte)
|
||||||
|
{
|
||||||
|
case 0x7d:
|
||||||
|
case 0x23:
|
||||||
|
case 0x24:
|
||||||
|
case 0x2a:
|
||||||
|
currentChecksum += 0x7d;
|
||||||
|
KdpSendByte(0x7d);
|
||||||
|
Byte ^= 0x20;
|
||||||
|
Sent++;
|
||||||
|
/* Fall-through */
|
||||||
|
default:
|
||||||
|
currentChecksum += Byte;
|
||||||
|
KdpSendByte(Byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
send_gdb_partial_memory(
|
||||||
|
_In_ const VOID* Buffer,
|
||||||
|
_In_ size_t Length)
|
||||||
|
{
|
||||||
|
const UCHAR* ptr = Buffer;
|
||||||
|
CHAR gdb_out[3];
|
||||||
|
|
||||||
|
gdb_out[2] = '\0';
|
||||||
|
|
||||||
|
while(Length--)
|
||||||
|
{
|
||||||
|
gdb_out[0] = hex_chars[(*ptr >> 4) & 0xf];
|
||||||
|
gdb_out[1] = hex_chars[*ptr++ & 0xf];
|
||||||
|
send_gdb_partial_packet(gdb_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KDSTATUS
|
||||||
|
send_gdb_memory(
|
||||||
|
_In_ const VOID* Buffer,
|
||||||
|
_In_ size_t Length)
|
||||||
|
{
|
||||||
|
start_gdb_packet();
|
||||||
|
send_gdb_partial_memory(Buffer, Length);
|
||||||
|
return finish_gdb_packet();
|
||||||
|
}
|
||||||
|
|
||||||
|
KDSTATUS
|
||||||
gdb_send_debug_io(
|
gdb_send_debug_io(
|
||||||
_In_ PSTRING String,
|
_In_ PSTRING String,
|
||||||
_In_ BOOLEAN WithPrefix)
|
_In_ BOOLEAN WithPrefix)
|
||||||
{
|
{
|
||||||
UCHAR ack;
|
CHAR gdb_out[3];
|
||||||
|
|
||||||
do {
|
|
||||||
CHAR* ptr = String->Buffer;
|
CHAR* ptr = String->Buffer;
|
||||||
CHAR check_sum = 0;
|
|
||||||
USHORT Length = String->Length;
|
USHORT Length = String->Length;
|
||||||
CHAR Byte;
|
|
||||||
|
|
||||||
KdpSendByte('$');
|
gdb_out[2] = '\0';
|
||||||
|
|
||||||
|
start_gdb_packet();
|
||||||
|
|
||||||
if (WithPrefix)
|
if (WithPrefix)
|
||||||
{
|
{
|
||||||
KdpSendByte('O');
|
send_gdb_partial_packet("O");
|
||||||
check_sum = 'O';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send the data */
|
/* Send the data */
|
||||||
while (Length--)
|
while (Length--)
|
||||||
{
|
{
|
||||||
Byte = hex_chars[(*ptr >> 4) & 0xf];
|
gdb_out[0] = hex_chars[(*ptr >> 4) & 0xf];
|
||||||
KdpSendByte(Byte);
|
gdb_out[1] = hex_chars[*ptr++ & 0xf];
|
||||||
check_sum += Byte;
|
send_gdb_partial_packet(gdb_out);
|
||||||
Byte = hex_chars[*ptr++ & 0xf];
|
|
||||||
KdpSendByte(Byte);
|
|
||||||
check_sum += Byte;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* append check sum */
|
return finish_gdb_packet();
|
||||||
KdpSendByte('#');
|
|
||||||
KdpSendByte(hex_chars[(check_sum >> 4) & 0xf]);
|
|
||||||
KdpSendByte(hex_chars[check_sum & 0xf]);
|
|
||||||
|
|
||||||
/* Wait for acknowledgement */
|
|
||||||
if (KdpReceiveByte(&ack) != KdPacketReceived)
|
|
||||||
{
|
|
||||||
KD_DEBUGGER_NOT_PRESENT = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (ack != '+');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
KDSTATUS
|
||||||
gdb_send_exception()
|
gdb_send_exception()
|
||||||
{
|
{
|
||||||
char gdb_out[1024];
|
char gdb_out[1024];
|
||||||
|
@ -185,6 +211,9 @@ gdb_send_exception()
|
||||||
else
|
else
|
||||||
ptr += sprintf(ptr, "05");
|
ptr += sprintf(ptr, "05");
|
||||||
|
|
||||||
|
if (CurrentStateChange.NewState == DbgKdLoadSymbolsStateChange)
|
||||||
|
ptr += sprintf(ptr, "library:");
|
||||||
|
|
||||||
#if MONOPROCESS
|
#if MONOPROCESS
|
||||||
ptr += sprintf(ptr, "thread:%" PRIxPTR ";",
|
ptr += sprintf(ptr, "thread:%" PRIxPTR ";",
|
||||||
handle_to_gdb_tid(PsGetThreadId(Thread)));
|
handle_to_gdb_tid(PsGetThreadId(Thread)));
|
||||||
|
@ -193,8 +222,9 @@ gdb_send_exception()
|
||||||
handle_to_gdb_pid(PsGetThreadProcessId(Thread)),
|
handle_to_gdb_pid(PsGetThreadProcessId(Thread)),
|
||||||
handle_to_gdb_tid(PsGetThreadId(Thread)));
|
handle_to_gdb_tid(PsGetThreadId(Thread)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
|
ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
|
||||||
send_gdb_packet(gdb_out);
|
return send_gdb_packet(gdb_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -82,11 +82,11 @@ ctx_to_reg(CONTEXT* ctx, enum reg_name name, unsigned short* size)
|
||||||
static
|
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)
|
||||||
{
|
|
||||||
/* See if the guy got a stack */
|
|
||||||
if (Thread->Tcb.InitialStack == NULL)
|
|
||||||
{
|
{
|
||||||
static const void* NullValue = NULL;
|
static const void* NullValue = NULL;
|
||||||
|
|
||||||
|
if (!Thread->Tcb.InitialStack)
|
||||||
|
{
|
||||||
/* Terminated thread ? */
|
/* Terminated thread ? */
|
||||||
switch (reg_name)
|
switch (reg_name)
|
||||||
{
|
{
|
||||||
|
@ -130,28 +130,33 @@ thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The thread was not yet scheduled */
|
static PULONG Esp;
|
||||||
|
Esp = Thread->Tcb.KernelStack;
|
||||||
*size = 4;
|
*size = 4;
|
||||||
switch(reg_name)
|
switch(reg_name)
|
||||||
{
|
{
|
||||||
case ESP: return &Thread->Tcb.KernelStack;
|
case EBP: return &Esp[3];
|
||||||
case EBP: return &((ULONG*)Thread->Tcb.KernelStack)[4];
|
case ESP: return &Esp;
|
||||||
case EIP: return &Thread->StartAddress;
|
case EIP: return &NullValue;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
KDSTATUS
|
||||||
gdb_send_registers(void)
|
gdb_send_registers(void)
|
||||||
{
|
{
|
||||||
CHAR Registers[16*8 + 1];
|
CHAR RegisterStr[9];
|
||||||
UCHAR* RegisterPtr;
|
UCHAR* RegisterPtr;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned short size;
|
unsigned short size;
|
||||||
CHAR* ptr = Registers;
|
|
||||||
|
RegisterStr[8] = '\0';
|
||||||
|
|
||||||
|
start_gdb_packet();
|
||||||
|
|
||||||
KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
|
KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
|
||||||
KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
|
KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
|
||||||
|
@ -161,14 +166,16 @@ gdb_send_registers(void)
|
||||||
for(i=0; i < 16; i++)
|
for(i=0; i < 16; i++)
|
||||||
{
|
{
|
||||||
RegisterPtr = ctx_to_reg(&CurrentContext, i, &size);
|
RegisterPtr = ctx_to_reg(&CurrentContext, i, &size);
|
||||||
*ptr++ = hex_chars[RegisterPtr[0] >> 4];
|
RegisterStr[0] = hex_chars[RegisterPtr[0] >> 4];
|
||||||
*ptr++ = hex_chars[RegisterPtr[0] & 0xF];
|
RegisterStr[1] = hex_chars[RegisterPtr[0] & 0xF];
|
||||||
*ptr++ = hex_chars[RegisterPtr[1] >> 4];
|
RegisterStr[2] = hex_chars[RegisterPtr[1] >> 4];
|
||||||
*ptr++ = hex_chars[RegisterPtr[1] & 0xF];
|
RegisterStr[3] = hex_chars[RegisterPtr[1] & 0xF];
|
||||||
*ptr++ = hex_chars[RegisterPtr[2] >> 4];
|
RegisterStr[4] = hex_chars[RegisterPtr[2] >> 4];
|
||||||
*ptr++ = hex_chars[RegisterPtr[2] & 0xF];
|
RegisterStr[5] = hex_chars[RegisterPtr[2] & 0xF];
|
||||||
*ptr++ = hex_chars[RegisterPtr[3] >> 4];
|
RegisterStr[6] = hex_chars[RegisterPtr[3] >> 4];
|
||||||
*ptr++ = hex_chars[RegisterPtr[3] & 0xF];
|
RegisterStr[7] = hex_chars[RegisterPtr[3] & 0xF];
|
||||||
|
|
||||||
|
send_gdb_partial_packet(RegisterStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -180,8 +187,8 @@ gdb_send_registers(void)
|
||||||
if (DbgThread == NULL)
|
if (DbgThread == NULL)
|
||||||
{
|
{
|
||||||
/* Thread is dead */
|
/* Thread is dead */
|
||||||
send_gdb_packet("E03");
|
send_gdb_partial_packet("E03");
|
||||||
return;
|
return finish_gdb_packet();
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0; i < 16; i++)
|
for(i=0; i < 16; i++)
|
||||||
|
@ -189,26 +196,29 @@ gdb_send_registers(void)
|
||||||
RegisterPtr = thread_to_reg(DbgThread, i, &size);
|
RegisterPtr = thread_to_reg(DbgThread, i, &size);
|
||||||
if (RegisterPtr)
|
if (RegisterPtr)
|
||||||
{
|
{
|
||||||
*ptr++ = hex_chars[RegisterPtr[0] >> 4];
|
RegisterPtr = ctx_to_reg(&CurrentContext, i, &size);
|
||||||
*ptr++ = hex_chars[RegisterPtr[0] & 0xF];
|
RegisterStr[0] = hex_chars[RegisterPtr[0] >> 4];
|
||||||
*ptr++ = hex_chars[RegisterPtr[1] >> 4];
|
RegisterStr[1] = hex_chars[RegisterPtr[0] & 0xF];
|
||||||
*ptr++ = hex_chars[RegisterPtr[1] & 0xF];
|
RegisterStr[2] = hex_chars[RegisterPtr[1] >> 4];
|
||||||
*ptr++ = hex_chars[RegisterPtr[2] >> 4];
|
RegisterStr[3] = hex_chars[RegisterPtr[1] & 0xF];
|
||||||
*ptr++ = hex_chars[RegisterPtr[2] & 0xF];
|
RegisterStr[4] = hex_chars[RegisterPtr[2] >> 4];
|
||||||
*ptr++ = hex_chars[RegisterPtr[3] >> 4];
|
RegisterStr[5] = hex_chars[RegisterPtr[2] & 0xF];
|
||||||
*ptr++ = hex_chars[RegisterPtr[3] & 0xF];
|
RegisterStr[6] = hex_chars[RegisterPtr[3] >> 4];
|
||||||
|
RegisterStr[7] = hex_chars[RegisterPtr[3] & 0xF];
|
||||||
|
|
||||||
|
send_gdb_partial_packet(RegisterStr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ptr += sprintf(ptr, "xxxxxxxx");
|
send_gdb_partial_packet("xxxxxxxx");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*ptr = '\0';
|
|
||||||
send_gdb_packet(Registers);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
return finish_gdb_packet();
|
||||||
|
}
|
||||||
|
|
||||||
|
KDSTATUS
|
||||||
gdb_send_register(void)
|
gdb_send_register(void)
|
||||||
{
|
{
|
||||||
enum reg_name reg_name;
|
enum reg_name reg_name;
|
||||||
|
@ -233,8 +243,7 @@ gdb_send_register(void)
|
||||||
if (DbgThread == NULL)
|
if (DbgThread == NULL)
|
||||||
{
|
{
|
||||||
/* Thread is dead */
|
/* Thread is dead */
|
||||||
send_gdb_packet("E03");
|
return send_gdb_packet("E03");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = thread_to_reg(DbgThread, reg_name, &size);
|
ptr = thread_to_reg(DbgThread, reg_name, &size);
|
||||||
|
@ -243,11 +252,12 @@ gdb_send_register(void)
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
/* Undefined. Let's assume 32 bit register */
|
/* Undefined. Let's assume 32 bit register */
|
||||||
send_gdb_packet("xxxxxxxx");
|
return send_gdb_packet("xxxxxxxx");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
send_gdb_memory(ptr, size);
|
KDDBGPRINT("KDDBG : Sending registers as memory.\n");
|
||||||
|
return send_gdb_memory(ptr, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,10 +80,15 @@ KDSTATUS NTAPI gdb_receive_packet(_Inout_ PKD_CONTEXT KdContext);
|
||||||
char hex_value(char ch);
|
char hex_value(char ch);
|
||||||
|
|
||||||
/* gdb_send.c */
|
/* gdb_send.c */
|
||||||
void send_gdb_packet(_In_ CHAR* Buffer);
|
KDSTATUS send_gdb_packet(_In_ const CHAR* Buffer);
|
||||||
void send_gdb_memory(_In_ VOID* Buffer, size_t Length);
|
void start_gdb_packet(void);
|
||||||
void gdb_send_debug_io(_In_ PSTRING String, _In_ BOOLEAN WithPrefix);
|
void send_gdb_partial_packet(_In_ const CHAR* Buffer);
|
||||||
void gdb_send_exception(void);
|
KDSTATUS finish_gdb_packet(void);
|
||||||
|
KDSTATUS send_gdb_memory(_In_ const VOID* Buffer, size_t Length);
|
||||||
|
void send_gdb_partial_memory(_In_ const VOID* Buffer, _In_ size_t Length);
|
||||||
|
ULONG send_gdb_partial_binary(_In_ const VOID* Buffer, _In_ size_t Length);
|
||||||
|
KDSTATUS gdb_send_debug_io(_In_ PSTRING String, _In_ BOOLEAN WithPrefix);
|
||||||
|
KDSTATUS gdb_send_exception(void);
|
||||||
void send_gdb_ntstatus(_In_ NTSTATUS Status);
|
void send_gdb_ntstatus(_In_ NTSTATUS Status);
|
||||||
extern const char hex_chars[];
|
extern const char hex_chars[];
|
||||||
|
|
||||||
|
@ -98,6 +103,7 @@ 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 LIST_ENTRY* ProcessListHead;
|
||||||
|
extern LIST_ENTRY* ModuleListHead;
|
||||||
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 */
|
||||||
|
@ -111,8 +117,8 @@ extern PEPROCESS find_process( _In_ UINT_PTR Pid);
|
||||||
extern PETHREAD find_thread(_In_ UINT_PTR Pid, _In_ UINT_PTR Tid);
|
extern PETHREAD find_thread(_In_ UINT_PTR Pid, _In_ UINT_PTR Tid);
|
||||||
|
|
||||||
/* arch_sup.c */
|
/* arch_sup.c */
|
||||||
extern void gdb_send_register(void);
|
extern KDSTATUS gdb_send_register(void);
|
||||||
extern void gdb_send_registers(void);
|
extern KDSTATUS gdb_send_registers(void);
|
||||||
|
|
||||||
/* Architecture specific defines. See ntoskrnl/include/internal/arch/ke.h */
|
/* Architecture specific defines. See ntoskrnl/include/internal/arch/ke.h */
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
|
|
|
@ -20,6 +20,7 @@ static BOOLEAN InException = FALSE;
|
||||||
DBGKD_GET_VERSION64 KdVersion;
|
DBGKD_GET_VERSION64 KdVersion;
|
||||||
KDDEBUGGER_DATA64* KdDebuggerDataBlock;
|
KDDEBUGGER_DATA64* KdDebuggerDataBlock;
|
||||||
LIST_ENTRY* ProcessListHead;
|
LIST_ENTRY* ProcessListHead;
|
||||||
|
LIST_ENTRY* ModuleListHead;
|
||||||
/* 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;
|
||||||
|
@ -139,11 +140,6 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
|
||||||
switch (StateChange->NewState)
|
switch (StateChange->NewState)
|
||||||
{
|
{
|
||||||
case DbgKdLoadSymbolsStateChange:
|
case DbgKdLoadSymbolsStateChange:
|
||||||
{
|
|
||||||
/* We don't care about symbols loading */
|
|
||||||
KdpManipulateStateHandler = ContinueManipulateStateHandler;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DbgKdExceptionStateChange:
|
case DbgKdExceptionStateChange:
|
||||||
{
|
{
|
||||||
PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
|
PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
|
||||||
|
@ -264,6 +260,7 @@ GetVersionSendHandler(
|
||||||
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;
|
ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer;
|
||||||
|
ModuleListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsLoadedModuleList.Pointer;
|
||||||
|
|
||||||
/* Now we can get the context for the current state */
|
/* Now we can get the context for the current state */
|
||||||
KdpSendPacketHandler = NULL;
|
KdpSendPacketHandler = NULL;
|
||||||
|
@ -363,6 +360,8 @@ KdReceivePacket(
|
||||||
_Out_ PULONG DataLength,
|
_Out_ PULONG DataLength,
|
||||||
_Inout_ PKD_CONTEXT KdContext)
|
_Inout_ PKD_CONTEXT KdContext)
|
||||||
{
|
{
|
||||||
|
KDDBGPRINT("KdReceivePacket.\n");
|
||||||
|
|
||||||
if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
|
if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
|
||||||
{
|
{
|
||||||
return KdpPollBreakIn();
|
return KdpPollBreakIn();
|
||||||
|
@ -382,7 +381,10 @@ KdReceivePacket(
|
||||||
|
|
||||||
/* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
|
/* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
|
||||||
if (KdpManipulateStateHandler != NULL)
|
if (KdpManipulateStateHandler != NULL)
|
||||||
|
{
|
||||||
|
KDDBGPRINT("KDGBD: We have a manipulate state handler.\n");
|
||||||
return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
|
return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
|
||||||
|
}
|
||||||
|
|
||||||
/* Receive data from GDB and interpret it */
|
/* Receive data from GDB and interpret it */
|
||||||
return gdb_receive_and_interpret_packet(State, MessageData, DataLength, KdContext);
|
return gdb_receive_and_interpret_packet(State, MessageData, DataLength, KdContext);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue