- 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:
Jérôme Gardou 2016-09-01 22:58:15 +00:00
parent 24834c0492
commit 9598f87c7c
5 changed files with 394 additions and 288 deletions

View file

@ -20,6 +20,13 @@ static struct
UINT_PTR gdb_dbg_pid;
UINT_PTR gdb_dbg_tid;
static inline
KDSTATUS
LOOP_IF_SUCCESS(x)
{
return (x == KdPacketReceived) ? (KDSTATUS)-1 : x;
}
/* PRIVATE FUNCTIONS **********************************************************/
static
UINT_PTR
@ -58,9 +65,11 @@ hex_to_address(char* buffer)
/* H* packets */
static
void
KDSTATUS
handle_gdb_set_thread(void)
{
KDSTATUS Status;
switch (gdb_input[1])
{
case 'c':
@ -68,7 +77,7 @@ handle_gdb_set_thread(void)
gdb_run_tid = (ULONG_PTR)-1;
else
gdb_run_tid = hex_to_tid(&gdb_input[2]);
send_gdb_packet("OK");
Status = send_gdb_packet("OK");
break;
case 'g':
KDDBGPRINT("Setting debug thread: %s.\n", gdb_input);
@ -98,20 +107,23 @@ handle_gdb_set_thread(void)
gdb_dbg_tid = hex_to_tid(ptr);
}
#endif
send_gdb_packet("OK");
Status = send_gdb_packet("OK");
break;
default:
KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input);
send_gdb_packet("");
Status = send_gdb_packet("");
}
return Status;
}
static
void
KDSTATUS
handle_gdb_thread_alive(void)
{
ULONG_PTR Pid, Tid;
PETHREAD Thread;
KDSTATUS Status;
#if MONOPROCESS
Pid = 0;
@ -131,45 +143,44 @@ handle_gdb_thread_alive(void)
Thread = find_thread(Pid, Tid);
if (Thread != NULL)
send_gdb_packet("OK");
Status = send_gdb_packet("OK");
else
send_gdb_packet("E03");
Status = send_gdb_packet("E03");
return Status;
}
/* q* packets */
static
void
KDSTATUS
handle_gdb_query(void)
{
if (strncmp(gdb_input, "qSupported:", 11) == 0)
{
#if MONOPROCESS
send_gdb_packet("PacketSize=1000;");
return send_gdb_packet("PacketSize=1000;qXfer:libraries:read+;");
#else
send_gdb_packet("PacketSize=1000;multiprocess+;");
return send_gdb_packet("PacketSize=1000;multiprocess+;qXfer:libraries:read+;");
#endif
return;
}
if (strncmp(gdb_input, "qAttached", 9) == 0)
{
#if MONOPROCESS
send_gdb_packet("1");
return send_gdb_packet("1");
#else
UINT_PTR queried_pid = hex_to_pid(&gdb_input[10]);
/* Let's say we created system process */
if (gdb_pid_to_handle(queried_pid) == NULL)
send_gdb_packet("0");
return send_gdb_packet("0");
else
send_gdb_packet("1");
return send_gdb_packet("1");
#endif
return;
}
if (strncmp(gdb_input, "qRcmd,", 6) == 0)
{
send_gdb_packet("OK");
return;
return send_gdb_packet("OK");
}
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_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
#endif
send_gdb_packet(gdb_out);
return;
return send_gdb_packet(gdb_out);
}
if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0)
|| (strncmp(gdb_input, "qsThreadInfo", 12) == 0))
if (strncmp(gdb_input, "qfThreadInfo", 12) == 0)
{
BOOLEAN FirstThread = TRUE;
PEPROCESS Process;
PETHREAD Thread;
char gdb_out[1024];
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;
CurrentThreadEntry = NULL;
FirstThread = FALSE;
}
char gdb_out[40];
LIST_ENTRY* CurrentProcessEntry;
CurrentProcessEntry = ProcessListHead->Flink;
if (CurrentProcessEntry == NULL) /* Ps is not initialized */
{
send_gdb_packet(Resuming ? "l" : gdb_out);
return;
#if MONOPROCESS
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 */
for ( ;
CurrentProcessEntry != ProcessListHead;
CurrentProcessEntry = CurrentProcessEntry->Flink)
{
LIST_ENTRY* CurrentThreadEntry;
Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
if (CurrentThreadEntry != NULL)
CurrentThreadEntry = CurrentThreadEntry->Flink;
else
CurrentThreadEntry = Process->ThreadListHead.Flink;
/* List threads from this process */
for ( ;
for ( CurrentThreadEntry = Process->ThreadListHead.Flink;
CurrentThreadEntry != &Process->ThreadListHead;
CurrentThreadEntry = CurrentThreadEntry->Flink)
{
Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry);
/* See if we should add a comma */
if (FirstThread)
{
FirstThread = FALSE;
}
else
{
*ptr++ = ',';
}
PETHREAD Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry);
#if MONOPROCESS
ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
"%p",
handle_to_gdb_tid(Thread->Cid.UniqueThread));
_snprintf(gdb_out, 40, ",%p", handle_to_gdb_tid(Thread->Cid.UniqueThread));
#else
ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
"p%p.%p",
_snprintf(gdb_out, 40, ",p%p.%p",
handle_to_gdb_pid(Process->UniqueProcessId),
handle_to_gdb_tid(Thread->Cid.UniqueThread));
#endif
if (ptr > (gdb_out + 1024))
{
/* send what we got */
send_gdb_packet(gdb_out);
/* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
return;
}
send_gdb_partial_packet(gdb_out);
}
/* We're done for this process */
CurrentThreadEntry = NULL;
}
if (gdb_out[1] == '\0')
{
/* We didn't iterate over anything, meaning we were already done */
send_gdb_packet("l");
}
else
{
send_gdb_packet(gdb_out);
}
/* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
return;
return finish_gdb_packet();
}
if (strncmp(gdb_input, "qsThreadInfo", 12) == 0)
{
/* We sent the whole thread list on first qfThreadInfo call */
return send_gdb_packet("l");
}
if (strncmp(gdb_input, "qThreadExtraInfo,", 17) == 0)
@ -330,27 +298,117 @@ handle_gdb_query(void)
String.Length = sprintf(out_string, "%.*s", 16, Process->ImageFileName);
}
gdb_send_debug_io(&String, FALSE);
return;
return gdb_send_debug_io(&String, FALSE);
}
if (strncmp(gdb_input, "qOffsets", 8) == 0)
{
/* We load ntoskrnl at 0x80800000 while compiling it at 0x00800000 base adress */
send_gdb_packet("TextSeg=80000000");
return;
return send_gdb_packet("TextSeg=80000000");
}
if (strcmp(gdb_input, "qTStatus") == 0)
{
/* No tracepoint support */
send_gdb_packet("T0");
return;
return send_gdb_packet("T0");
}
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);
send_gdb_packet("");
return;
return send_gdb_packet("");
}
#if 0
@ -413,7 +471,9 @@ ReadMemorySendHandler(
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
#endif
{
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
/* Only do this if Ps is initialized */
if (ProcessListHead->Flink)
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
}
}
@ -442,16 +502,14 @@ handle_gdb_read_mem(
if (AttachedThread == NULL)
{
KDDBGPRINT("The current GDB debug thread is invalid!");
send_gdb_packet("E03");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
}
AttachedProcess = AttachedThread->Tcb.Process;
if (AttachedProcess == NULL)
{
KDDBGPRINT("The current GDB debug thread is invalid!");
send_gdb_packet("E03");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
}
__writecr3(AttachedProcess->DirectoryTableBase[0]);
}
@ -462,10 +520,11 @@ handle_gdb_read_mem(
if (AttachedProcess == NULL)
{
KDDBGPRINT("The current GDB debug thread is invalid!");
send_gdb_packet("E03");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
}
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
/* Only do this if Ps is initialized */
if (ProcessListHead->Flink)
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
}
#endif
@ -474,7 +533,6 @@ handle_gdb_read_mem(
/* KD will reply with KdSendPacket. Catch it */
KdpSendPacketHandler = ReadMemorySendHandler;
return KdPacketReceived;
}
@ -514,7 +572,9 @@ WriteMemorySendHandler(
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
#endif
{
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
/* Only do this if Ps is initialized */
if (ProcessListHead->Flink)
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
}
}
@ -546,16 +606,14 @@ handle_gdb_write_mem(
if (AttachedThread == NULL)
{
KDDBGPRINT("The current GDB debug thread is invalid!");
send_gdb_packet("E03");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
}
AttachedProcess = AttachedThread->Tcb.Process;
if (AttachedProcess == NULL)
{
KDDBGPRINT("The current GDB debug thread is invalid!");
send_gdb_packet("E03");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
}
__writecr3(AttachedProcess->DirectoryTableBase[0]);
}
@ -566,10 +624,11 @@ handle_gdb_write_mem(
if (AttachedProcess == NULL)
{
KDDBGPRINT("The current GDB debug thread is invalid!");
send_gdb_packet("E03");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E03"));
}
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
/* Only do this if Ps is initialized */
if (ProcessListHead->Flink)
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
}
#endif
@ -578,8 +637,7 @@ handle_gdb_write_mem(
if (BufferLength == 0)
{
/* Nothing to do */
send_gdb_packet("OK");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("OK"));
}
State->u.WriteMemory.TransferCount = BufferLength;
@ -613,7 +671,6 @@ handle_gdb_write_mem(
/* KD will reply with KdSendPacket. Catch it */
KdpSendPacketHandler = WriteMemorySendHandler;
return KdPacketReceived;
}
@ -698,8 +755,7 @@ handle_gdb_insert_breakpoint(
{
/* We don't have a way to keep track of this break point. Fail. */
KDDBGPRINT("No breakpoint slot available!\n");
send_gdb_packet("E01");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
}
State->ApiNumber = DbgKdWriteBreakPointApi;
@ -713,8 +769,7 @@ handle_gdb_insert_breakpoint(
}
KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
send_gdb_packet("E01");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
}
static
@ -793,8 +848,7 @@ handle_gdb_remove_breakpoint(
if (Handle == 0)
{
KDDBGPRINT("Received %s, but breakpoint was never inserted ?!\n", gdb_input);
send_gdb_packet("E01");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
}
State->ApiNumber = DbgKdRestoreBreakPointApi;
@ -808,8 +862,7 @@ handle_gdb_remove_breakpoint(
}
KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
send_gdb_packet("E01");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("E01"));
}
static
@ -820,8 +873,13 @@ handle_gdb_c(
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{
KDSTATUS Status;
/* 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)
{
@ -873,8 +931,7 @@ handle_gdb_v(
if (gdb_input[5] == '?')
{
/* Report what we support */
send_gdb_packet("vCont;c;s");
return (KDSTATUS)-1;
return LOOP_IF_SUCCESS(send_gdb_packet("vCont;c;s"));
}
if (strncmp(gdb_input, "vCont;c", 7) == 0)
@ -890,7 +947,7 @@ handle_gdb_v(
}
KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input);
return KdPacketReceived;
return LOOP_IF_SUCCESS(send_gdb_packet(""));
}
KDSTATUS
@ -904,8 +961,9 @@ gdb_receive_and_interpret_packet(
do
{
KDDBGPRINT("KDGBD: Receiving packet.\n");
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)
return Status;
@ -916,34 +974,34 @@ gdb_receive_and_interpret_packet(
{
case '?':
/* Send the Status */
gdb_send_exception();
Status = LOOP_IF_SUCCESS(gdb_send_exception());
break;
case '!':
send_gdb_packet("OK");
Status = LOOP_IF_SUCCESS(send_gdb_packet("OK"));
break;
case 'c':
Status = handle_gdb_c(State, MessageData, MessageLength, KdContext);
break;
case 'g':
gdb_send_registers();
Status = LOOP_IF_SUCCESS(gdb_send_registers());
break;
case 'H':
handle_gdb_set_thread();
Status = LOOP_IF_SUCCESS(handle_gdb_set_thread());
break;
case 'm':
Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
break;
case 'p':
gdb_send_register();
Status = LOOP_IF_SUCCESS(gdb_send_register());
break;
case 'q':
handle_gdb_query();
Status = LOOP_IF_SUCCESS(handle_gdb_query());
break;
case 's':
Status = handle_gdb_s(State, MessageData, MessageLength, KdContext);
break;
case 'T':
handle_gdb_thread_alive();
Status = LOOP_IF_SUCCESS(handle_gdb_thread_alive());
break;
case 'v':
Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
@ -960,7 +1018,7 @@ gdb_receive_and_interpret_packet(
default:
/* We don't know how to handle this request. */
KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
send_gdb_packet("");
Status = LOOP_IF_SUCCESS(send_gdb_packet(""));
}
} while (Status == (KDSTATUS)-1);

View file

@ -9,6 +9,7 @@
/* LOCALS *********************************************************************/
const char hex_chars[] = "0123456789abcdef";
static CHAR currentChecksum = 0;
/* PRIVATE FUNCTIONS **********************************************************/
static
@ -48,126 +49,151 @@ exception_code_to_gdb(NTSTATUS code, char* out)
/* GLOBAL FUNCTIONS ***********************************************************/
void
send_gdb_packet(_In_ CHAR* Buffer)
start_gdb_packet(void)
{
UCHAR ack;
do {
CHAR* ptr = Buffer;
CHAR check_sum = 0;
KdpSendByte('$');
/* Calculate checksum */
check_sum = 0;
while (*ptr)
{
check_sum += *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 != '+');
/* Start the start byte and begin checksum calculation */
KdpSendByte('$');
currentChecksum = 0;
}
void
send_gdb_memory(
_In_ VOID* Buffer,
send_gdb_partial_packet(_In_ const CHAR* Buffer)
{
const CHAR* ptr = Buffer;
/* Update check sum and send */
while (*ptr)
{
currentChecksum += *ptr;
KdpSendByte(*ptr++);
}
}
KDSTATUS
finish_gdb_packet(void)
{
UCHAR ack;
KDSTATUS Status;
/* Send finish byte and append checksum */
KdpSendByte('#');
KdpSendByte(hex_chars[(currentChecksum >> 4) & 0xf]);
KdpSendByte(hex_chars[currentChecksum & 0xf]);
/* Wait for acknowledgement */
Status = KdpReceiveByte(&ack);
if (Status != KdPacketReceived)
{
KD_DEBUGGER_NOT_PRESENT = TRUE;
return Status;
}
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)
{
UCHAR ack;
const UCHAR* ptr = Buffer;
ULONG Sent = Length;
do {
CHAR* ptr = Buffer;
CHAR check_sum = 0;
size_t len = Length;
CHAR Byte;
while(Length--)
{
UCHAR Byte = *ptr++;
KdpSendByte('$');
/* Send the data */
check_sum = 0;
while (len--)
switch (Byte)
{
Byte = hex_chars[(*ptr >> 4) & 0xf];
KdpSendByte(Byte);
check_sum += Byte;
Byte = hex_chars[*ptr++ & 0xf];
KdpSendByte(Byte);
check_sum += Byte;
case 0x7d:
case 0x23:
case 0x24:
case 0x2a:
currentChecksum += 0x7d;
KdpSendByte(0x7d);
Byte ^= 0x20;
Sent++;
/* Fall-through */
default:
currentChecksum += Byte;
KdpSendByte(Byte);
}
}
/* append check sum */
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 != '+');
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(
_In_ PSTRING String,
_In_ BOOLEAN WithPrefix)
{
UCHAR ack;
CHAR gdb_out[3];
CHAR* ptr = String->Buffer;
USHORT Length = String->Length;
gdb_out[2] = '\0';
do {
CHAR* ptr = String->Buffer;
CHAR check_sum = 0;
USHORT Length = String->Length;
CHAR Byte;
start_gdb_packet();
KdpSendByte('$');
if (WithPrefix)
{
send_gdb_partial_packet("O");
}
if (WithPrefix)
{
KdpSendByte('O');
check_sum = 'O';
}
/* Send the data */
while (Length--)
{
gdb_out[0] = hex_chars[(*ptr >> 4) & 0xf];
gdb_out[1] = hex_chars[*ptr++ & 0xf];
send_gdb_partial_packet(gdb_out);
}
/* Send the data */
while (Length--)
{
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(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 != '+');
return finish_gdb_packet();
}
void
KDSTATUS
gdb_send_exception()
{
char gdb_out[1024];
@ -185,6 +211,9 @@ gdb_send_exception()
else
ptr += sprintf(ptr, "05");
if (CurrentStateChange.NewState == DbgKdLoadSymbolsStateChange)
ptr += sprintf(ptr, "library:");
#if MONOPROCESS
ptr += sprintf(ptr, "thread:%" PRIxPTR ";",
handle_to_gdb_tid(PsGetThreadId(Thread)));
@ -193,8 +222,9 @@ gdb_send_exception()
handle_to_gdb_pid(PsGetThreadProcessId(Thread)),
handle_to_gdb_tid(PsGetThreadId(Thread)));
#endif
ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
send_gdb_packet(gdb_out);
return send_gdb_packet(gdb_out);
}
void

View file

@ -83,10 +83,10 @@ static
void*
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;
if (!Thread->Tcb.InitialStack)
{
static const void* NullValue = NULL;
/* Terminated thread ? */
switch (reg_name)
{
@ -130,28 +130,33 @@ thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size)
}
else
{
/* The thread was not yet scheduled */
static PULONG Esp;
Esp = Thread->Tcb.KernelStack;
*size = 4;
switch(reg_name)
{
case ESP: return &Thread->Tcb.KernelStack;
case EBP: return &((ULONG*)Thread->Tcb.KernelStack)[4];
case EIP: return &Thread->StartAddress;
case EBP: return &Esp[3];
case ESP: return &Esp;
case EIP: return &NullValue;
default:
return NULL;
}
}
return NULL;
}
void
KDSTATUS
gdb_send_registers(void)
{
CHAR Registers[16*8 + 1];
CHAR RegisterStr[9];
UCHAR* RegisterPtr;
unsigned i;
unsigned short size;
CHAR* ptr = Registers;
RegisterStr[8] = '\0';
start_gdb_packet();
KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
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++)
{
RegisterPtr = ctx_to_reg(&CurrentContext, i, &size);
*ptr++ = hex_chars[RegisterPtr[0] >> 4];
*ptr++ = hex_chars[RegisterPtr[0] & 0xF];
*ptr++ = hex_chars[RegisterPtr[1] >> 4];
*ptr++ = hex_chars[RegisterPtr[1] & 0xF];
*ptr++ = hex_chars[RegisterPtr[2] >> 4];
*ptr++ = hex_chars[RegisterPtr[2] & 0xF];
*ptr++ = hex_chars[RegisterPtr[3] >> 4];
*ptr++ = hex_chars[RegisterPtr[3] & 0xF];
RegisterStr[0] = hex_chars[RegisterPtr[0] >> 4];
RegisterStr[1] = hex_chars[RegisterPtr[0] & 0xF];
RegisterStr[2] = hex_chars[RegisterPtr[1] >> 4];
RegisterStr[3] = hex_chars[RegisterPtr[1] & 0xF];
RegisterStr[4] = hex_chars[RegisterPtr[2] >> 4];
RegisterStr[5] = hex_chars[RegisterPtr[2] & 0xF];
RegisterStr[6] = hex_chars[RegisterPtr[3] >> 4];
RegisterStr[7] = hex_chars[RegisterPtr[3] & 0xF];
send_gdb_partial_packet(RegisterStr);
}
}
else
@ -180,8 +187,8 @@ gdb_send_registers(void)
if (DbgThread == NULL)
{
/* Thread is dead */
send_gdb_packet("E03");
return;
send_gdb_partial_packet("E03");
return finish_gdb_packet();
}
for(i=0; i < 16; i++)
@ -189,26 +196,29 @@ gdb_send_registers(void)
RegisterPtr = thread_to_reg(DbgThread, i, &size);
if (RegisterPtr)
{
*ptr++ = hex_chars[RegisterPtr[0] >> 4];
*ptr++ = hex_chars[RegisterPtr[0] & 0xF];
*ptr++ = hex_chars[RegisterPtr[1] >> 4];
*ptr++ = hex_chars[RegisterPtr[1] & 0xF];
*ptr++ = hex_chars[RegisterPtr[2] >> 4];
*ptr++ = hex_chars[RegisterPtr[2] & 0xF];
*ptr++ = hex_chars[RegisterPtr[3] >> 4];
*ptr++ = hex_chars[RegisterPtr[3] & 0xF];
RegisterPtr = ctx_to_reg(&CurrentContext, i, &size);
RegisterStr[0] = hex_chars[RegisterPtr[0] >> 4];
RegisterStr[1] = hex_chars[RegisterPtr[0] & 0xF];
RegisterStr[2] = hex_chars[RegisterPtr[1] >> 4];
RegisterStr[3] = hex_chars[RegisterPtr[1] & 0xF];
RegisterStr[4] = hex_chars[RegisterPtr[2] >> 4];
RegisterStr[5] = hex_chars[RegisterPtr[2] & 0xF];
RegisterStr[6] = hex_chars[RegisterPtr[3] >> 4];
RegisterStr[7] = hex_chars[RegisterPtr[3] & 0xF];
send_gdb_partial_packet(RegisterStr);
}
else
{
ptr += sprintf(ptr, "xxxxxxxx");
send_gdb_partial_packet("xxxxxxxx");
}
}
}
*ptr = '\0';
send_gdb_packet(Registers);
return finish_gdb_packet();
}
void
KDSTATUS
gdb_send_register(void)
{
enum reg_name reg_name;
@ -233,8 +243,7 @@ gdb_send_register(void)
if (DbgThread == NULL)
{
/* Thread is dead */
send_gdb_packet("E03");
return;
return send_gdb_packet("E03");
}
ptr = thread_to_reg(DbgThread, reg_name, &size);
@ -243,11 +252,12 @@ gdb_send_register(void)
if (!ptr)
{
/* Undefined. Let's assume 32 bit register */
send_gdb_packet("xxxxxxxx");
return send_gdb_packet("xxxxxxxx");
}
else
{
send_gdb_memory(ptr, size);
KDDBGPRINT("KDDBG : Sending registers as memory.\n");
return send_gdb_memory(ptr, size);
}
}

View file

@ -19,7 +19,7 @@
#include <pstypes.h>
//#define KDDEBUG /* uncomment to enable debugging this dll */
// #define KDDEBUG /* uncomment to enable debugging this dll */
/* To undefine once https://sourceware.org/bugzilla/show_bug.cgi?id=17397 is resolved */
#define MONOPROCESS 1
@ -80,10 +80,15 @@ KDSTATUS NTAPI gdb_receive_packet(_Inout_ PKD_CONTEXT KdContext);
char hex_value(char ch);
/* gdb_send.c */
void send_gdb_packet(_In_ CHAR* Buffer);
void send_gdb_memory(_In_ VOID* Buffer, size_t Length);
void gdb_send_debug_io(_In_ PSTRING String, _In_ BOOLEAN WithPrefix);
void gdb_send_exception(void);
KDSTATUS send_gdb_packet(_In_ const CHAR* Buffer);
void start_gdb_packet(void);
void send_gdb_partial_packet(_In_ const CHAR* Buffer);
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);
extern const char hex_chars[];
@ -98,6 +103,7 @@ extern CONTEXT CurrentContext;
extern DBGKD_GET_VERSION64 KdVersion;
extern KDDEBUGGER_DATA64* KdDebuggerDataBlock;
extern LIST_ENTRY* ProcessListHead;
extern LIST_ENTRY* ModuleListHead;
extern KDP_SEND_HANDLER KdpSendPacketHandler;
extern KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler;
/* 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);
/* arch_sup.c */
extern void gdb_send_register(void);
extern void gdb_send_registers(void);
extern KDSTATUS gdb_send_register(void);
extern KDSTATUS gdb_send_registers(void);
/* Architecture specific defines. See ntoskrnl/include/internal/arch/ke.h */
#ifdef _M_IX86

View file

@ -20,6 +20,7 @@ static BOOLEAN InException = FALSE;
DBGKD_GET_VERSION64 KdVersion;
KDDEBUGGER_DATA64* KdDebuggerDataBlock;
LIST_ENTRY* ProcessListHead;
LIST_ENTRY* ModuleListHead;
/* Callbacks used to communicate with KD aside from GDB */
KDP_SEND_HANDLER KdpSendPacketHandler = FirstSendHandler;
KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
@ -139,11 +140,6 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
switch (StateChange->NewState)
{
case DbgKdLoadSymbolsStateChange:
{
/* We don't care about symbols loading */
KdpManipulateStateHandler = ContinueManipulateStateHandler;
break;
}
case DbgKdExceptionStateChange:
{
PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread;
@ -264,6 +260,7 @@ GetVersionSendHandler(
DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer;
ModuleListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsLoadedModuleList.Pointer;
/* Now we can get the context for the current state */
KdpSendPacketHandler = NULL;
@ -363,6 +360,8 @@ KdReceivePacket(
_Out_ PULONG DataLength,
_Inout_ PKD_CONTEXT KdContext)
{
KDDBGPRINT("KdReceivePacket.\n");
if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
{
return KdpPollBreakIn();
@ -382,7 +381,10 @@ KdReceivePacket(
/* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
if (KdpManipulateStateHandler != NULL)
{
KDDBGPRINT("KDGBD: We have a manipulate state handler.\n");
return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
}
/* Receive data from GDB and interpret it */
return gdb_receive_and_interpret_packet(State, MessageData, DataLength, KdContext);