- Turn this thing into something useful
   - Pretend we are only one process to GDB (making it a kernel-only debugger...) until the GDB team sorts this out
   - This is a kernel debugger stub you know. You didn't seriously pretend that recursive functions would be fine, did you ?
[NTOS:KD64]
 - Fix build
Pix or it din't happen : https://jira.reactos.org/secure/attachment/36322/source_level_debugging_ros.png

svn path=/trunk/; revision=72077
This commit is contained in:
Jérôme Gardou 2016-08-01 22:16:58 +00:00
parent 0f196e05cc
commit 9bb0e5a772
9 changed files with 373 additions and 182 deletions

View file

@ -9,9 +9,7 @@
/* LOCALS *********************************************************************/ /* LOCALS *********************************************************************/
static ULONG_PTR gdb_run_tid; static ULONG_PTR gdb_run_tid;
/* Keep track of where we are for qfThreadInfo/qsThreadInfo */
static LIST_ENTRY* CurrentProcessEntry;
static LIST_ENTRY* CurrentThreadEntry;
/* GLOBALS ********************************************************************/ /* GLOBALS ********************************************************************/
UINT_PTR gdb_dbg_pid; UINT_PTR gdb_dbg_pid;
@ -69,6 +67,17 @@ handle_gdb_set_thread(void)
break; break;
case 'g': case 'g':
KDDBGPRINT("Setting debug thread: %s.\n", gdb_input); KDDBGPRINT("Setting debug thread: %s.\n", gdb_input);
#if MONOPROCESS
gdb_dbg_pid = 0;
if (strncmp(&gdb_input[2], "-1", 2) == 0)
{
gdb_dbg_tid = (UINT_PTR)-1;
}
else
{
gdb_dbg_tid = hex_to_tid(&gdb_input[2]);
}
#else
if (strncmp(&gdb_input[2], "p-1", 3) == 0) if (strncmp(&gdb_input[2], "p-1", 3) == 0)
{ {
gdb_dbg_pid = (UINT_PTR)-1; gdb_dbg_pid = (UINT_PTR)-1;
@ -83,6 +92,7 @@ handle_gdb_set_thread(void)
else else
gdb_dbg_tid = hex_to_tid(ptr); gdb_dbg_tid = hex_to_tid(ptr);
} }
#endif
send_gdb_packet("OK"); send_gdb_packet("OK");
break; break;
default: default:
@ -91,20 +101,6 @@ handle_gdb_set_thread(void)
} }
} }
KDSTATUS
gdb_receive_and_interpret_packet(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{
KDSTATUS Status = gdb_receive_packet(KdContext);
if (Status != KdPacketReceived)
return Status;
return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
}
static static
void void
handle_gdb_thread_alive(void) handle_gdb_thread_alive(void)
@ -112,12 +108,20 @@ handle_gdb_thread_alive(void)
ULONG_PTR Pid, Tid; ULONG_PTR Pid, Tid;
PETHREAD Thread; PETHREAD Thread;
#if MONOPROCESS
Pid = 0;
Tid = hex_to_tid(&gdb_input[1]);
KDDBGPRINT("Checking if %p is alive.\n", Tid);
#else
Pid = hex_to_pid(&gdb_input[2]); Pid = hex_to_pid(&gdb_input[2]);
Tid = hex_to_tid(strstr(gdb_input, ".") + 1); Tid = hex_to_tid(strstr(gdb_input, ".") + 1);
/* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL. /* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
* So loop. */ * So loop. */
KDDBGPRINT("Checking if p%p.%p is alive.\n", Pid, Tid); KDDBGPRINT("Checking if p%p.%p is alive.\n", Pid, Tid);
#endif
Thread = find_thread(Pid, Tid); Thread = find_thread(Pid, Tid);
@ -129,40 +133,53 @@ handle_gdb_thread_alive(void)
/* q* packets */ /* q* packets */
static static
KDSTATUS void
handle_gdb_query( handle_gdb_query(void)
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{ {
if (strncmp(gdb_input, "qSupported:", 11) == 0) if (strncmp(gdb_input, "qSupported:", 11) == 0)
{ {
send_gdb_packet("PacketSize=4096;multiprocess+;"); #if MONOPROCESS
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); send_gdb_packet("PacketSize=1000;");
#else
send_gdb_packet("PacketSize=1000;multiprocess+;");
#endif
return;
} }
if (strncmp(gdb_input, "qAttached", 9) == 0) if (strncmp(gdb_input, "qAttached", 9) == 0)
{ {
/* Say no: We didn't attach, we create the process! */ #if MONOPROCESS
send_gdb_packet("0"); send_gdb_packet("1");
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); #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");
else
send_gdb_packet("1");
#endif
return;
} }
if (strncmp(gdb_input, "qRcmd,", 6) == 0) if (strncmp(gdb_input, "qRcmd,", 6) == 0)
{ {
send_gdb_packet("OK"); send_gdb_packet("OK");
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return;
} }
if (strcmp(gdb_input, "qC") == 0) if (strcmp(gdb_input, "qC") == 0)
{ {
char gdb_out[64]; char gdb_out[64];
#if MONOPROCESS
sprintf(gdb_out, "QC:%"PRIxPTR";",
handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));
#else
sprintf(gdb_out, "QC:p%"PRIxPTR".%"PRIxPTR";", sprintf(gdb_out, "QC:p%"PRIxPTR".%"PRIxPTR";",
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
send_gdb_packet(gdb_out); send_gdb_packet(gdb_out);
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return;
} }
if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0) if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0)
@ -174,82 +191,162 @@ handle_gdb_query(
char gdb_out[1024]; char gdb_out[1024];
char* ptr = gdb_out; char* ptr = gdb_out;
BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0; BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0;
/* Keep track of where we are. */
if (Resuming) static LIST_ENTRY* CurrentProcessEntry;
{ static LIST_ENTRY* CurrentThreadEntry;
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)
CurrentProcessEntry = CurrentProcessEntry->Flink;
}
else
CurrentProcessEntry = ProcessListHead->Flink;
if ((CurrentProcessEntry == ProcessListHead) ||
(CurrentProcessEntry == NULL)) /* Ps is not initialized */
{
/* We're almost done. Tell GDB about the idle thread */
send_gdb_packet("mp1.1");
CurrentProcessEntry = (LIST_ENTRY*)1;
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
}
Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
if (Resuming && CurrentThreadEntry != NULL)
CurrentThreadEntry = CurrentThreadEntry->Flink;
else
CurrentThreadEntry = Process->ThreadListHead.Flink;
ptr = gdb_out; ptr = gdb_out;
*ptr++ = 'm'; *ptr++ = 'm';
/* List threads from this process */ /* NULL terminate in case we got nothing more to iterate */
for ( ; *ptr = '\0';
CurrentThreadEntry != &Process->ThreadListHead;
CurrentThreadEntry = CurrentThreadEntry->Flink) if (!Resuming)
{ {
Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry); /* Initialize the entries */
CurrentProcessEntry = ProcessListHead->Flink;
CurrentThreadEntry = NULL;
/* See if we should add a comma */ /* Start with idle thread */
if (FirstThread) #if MONOPROCESS
{ ptr = gdb_out + sprintf(gdb_out, "m1");
FirstThread = FALSE; #else
} ptr = gdb_out + sprintf(gdb_out, "mp1.1");
else #endif
{ FirstThread = FALSE;
*ptr++ = ',';
}
ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
"p%p.%p",
handle_to_gdb_pid(Process->UniqueProcessId),
handle_to_gdb_tid(Thread->Cid.UniqueThread));
if (ptr > (gdb_out + 1024))
{
/* send what we got */
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);
}
} }
/* send the list for this process */ if (CurrentProcessEntry == NULL) /* Ps is not initialized */
send_gdb_packet(gdb_out); {
CurrentThreadEntry = NULL; send_gdb_packet(Resuming ? "l" : gdb_out);
return;
}
/* List all the processes */
for ( ;
CurrentProcessEntry != ProcessListHead;
CurrentProcessEntry = CurrentProcessEntry->Flink)
{
Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
if (CurrentThreadEntry != NULL)
CurrentThreadEntry = CurrentThreadEntry->Flink;
else
CurrentThreadEntry = Process->ThreadListHead.Flink;
/* List threads from this process */
for ( ;
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++ = ',';
}
#if MONOPROCESS
ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
"%p",
handle_to_gdb_tid(Thread->Cid.UniqueThread));
#else
ptr += _snprintf(ptr, 1024 - (ptr - gdb_out),
"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;
}
}
/* 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 */ /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return;
}
if (strncmp(gdb_input, "qThreadExtraInfo,", 17) == 0)
{
ULONG_PTR Pid, Tid;
PETHREAD Thread;
PEPROCESS Process;
char out_string[64];
STRING String = {0, 64, out_string};
KDDBGPRINT("Giving extra info for");
#if MONOPROCESS
Pid = 0;
Tid = hex_to_tid(&gdb_input[17]);
KDDBGPRINT(" %p.\n", Tid);
Thread = find_thread(Pid, Tid);
Process = CONTAINING_RECORD(Thread->Tcb.Process, EPROCESS, Pcb);
#else
Pid = hex_to_pid(&gdb_input[2]);
Tid = hex_to_tid(strstr(gdb_input, ".") + 1);
/* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
* So loop. */
KDDBGPRINT(" p%p.%p.\n", Pid, Tid);
Process = find_process(Pid);
Thread = find_thread(Pid, Tid);
#endif
if (PsGetThreadProcessId(Thread) == 0)
{
String.Length = sprintf(out_string, "SYSTEM");
}
else
{
String.Length = sprintf(out_string, "%.*s", 16, Process->ImageFileName);
}
gdb_send_debug_io(&String, FALSE);
return;
}
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;
}
if (strcmp(gdb_input, "qTStatus") == 0)
{
/* No tracepoint support */
send_gdb_packet("T0");
return;
} }
KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input); KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
send_gdb_packet(""); send_gdb_packet("");
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return;
} }
#if 0 #if 0
@ -305,11 +402,13 @@ ReadMemorySendHandler(
KdpSendPacketHandler = NULL; KdpSendPacketHandler = NULL;
KdpManipulateStateHandler = NULL; KdpManipulateStateHandler = NULL;
#if !MONOPROCESS
/* Reset the TLB */ /* Reset the TLB */
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())
{ {
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]); __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
} }
#endif
} }
static static
@ -328,6 +427,7 @@ handle_gdb_read_mem(
MessageData->Length = 0; MessageData->Length = 0;
*MessageLength = 0; *MessageLength = 0;
#if !MONOPROCESS
/* Set the TLB according to the process being read. Pid 0 means any process. */ /* Set the TLB according to the process being read. Pid 0 means any process. */
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId()) if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
{ {
@ -340,6 +440,7 @@ handle_gdb_read_mem(
} }
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]); __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
} }
#endif
State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]); State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1); State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
@ -362,16 +463,12 @@ handle_gdb_v(
{ {
if (gdb_input[5] == '?') if (gdb_input[5] == '?')
{ {
KDSTATUS Status;
/* Report what we support */ /* Report what we support */
send_gdb_packet("vCont;c;C;s;S"); send_gdb_packet("vCont;c;C;s;S");
Status = gdb_receive_packet(KdContext); return (KDSTATUS)-1;
if (Status != KdPacketReceived)
return Status;
return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
} }
if (strcmp(gdb_input, "vCont;c") == 0) if (strncmp(gdb_input, "vCont;c", 7) == 0)
{ {
DBGKM_EXCEPTION64* Exception = NULL; DBGKM_EXCEPTION64* Exception = NULL;
@ -404,41 +501,63 @@ handle_gdb_v(
return KdPacketReceived; return KdPacketReceived;
} }
/* GLOBAL FUNCTIONS ***********************************************************/
KDSTATUS KDSTATUS
gdb_interpret_input( gdb_receive_and_interpret_packet(
_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData, _Out_ PSTRING MessageData,
_Out_ PULONG MessageLength, _Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext) _Inout_ PKD_CONTEXT KdContext)
{ {
switch (gdb_input[0]) KDSTATUS Status;
do
{ {
case '?': Status = gdb_receive_packet(KdContext);
/* Send the Status */ KDDBGPRINT("KDGBD: Packet received with status %u\n", Status);
gdb_send_exception();
break; if (Status != KdPacketReceived)
case 'g': return Status;
return gdb_send_registers(State, MessageData, MessageLength, KdContext);
case 'H': Status = (KDSTATUS)-1;
handle_gdb_set_thread();
break; switch (gdb_input[0])
case 'm': {
return handle_gdb_read_mem(State, MessageData, MessageLength, KdContext); case '?':
case 'p': /* Send the Status */
return gdb_send_register(State, MessageData, MessageLength, KdContext); gdb_send_exception(TRUE);
case 'q': break;
return handle_gdb_query(State, MessageData, MessageLength, KdContext); case '!':
case 'T': send_gdb_packet("OK");
handle_gdb_thread_alive(); break;
break; case 'g':
case 'v': gdb_send_registers();
return handle_gdb_v(State, MessageData, MessageLength, KdContext); break;
default: case 'H':
/* We don't know how to handle this request. Maybe this is something for KD */ handle_gdb_set_thread();
State->ReturnStatus = STATUS_NOT_SUPPORTED; break;
KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input); case 'm':
return KdPacketReceived; Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext);
} break;
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); case 'p':
gdb_send_register();
break;
case 'q':
handle_gdb_query();
break;
case 'T':
handle_gdb_thread_alive();
break;
case 'v':
Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
break;
default:
/* We don't know how to handle this request. Maybe this is something for KD */
State->ReturnStatus = STATUS_NOT_SUPPORTED;
KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
return KdPacketReceived;
}
} while (Status == (KDSTATUS)-1);
return Status;
} }

View file

@ -42,6 +42,7 @@ gdb_receive_packet(_Inout_ PKD_CONTEXT KdContext)
return Status; return Status;
if (Byte == 0x03) if (Byte == 0x03)
{ {
KDDBGPRINT("BREAK!");
KdContext->KdpControlCPending = TRUE; KdContext->KdpControlCPending = TRUE;
return KdPacketNeedsResend; return KdPacketNeedsResend;
} }

View file

@ -123,22 +123,26 @@ send_gdb_memory(
void void
gdb_send_debug_io( gdb_send_debug_io(
_In_ PSTRING String) _In_ PSTRING String,
_In_ BOOLEAN WithPrefix)
{ {
UCHAR ack; UCHAR ack;
do { do {
CHAR* ptr = String->Buffer; CHAR* ptr = String->Buffer;
CHAR check_sum; CHAR check_sum = 0;
USHORT Length = String->Length; USHORT Length = String->Length;
CHAR Byte; CHAR Byte;
KdpSendByte('$'); KdpSendByte('$');
KdpSendByte('O'); if (WithPrefix)
{
KdpSendByte('O');
check_sum = 'O';
}
/* Send the data */ /* Send the data */
check_sum = 'O';
while (Length--) while (Length--)
{ {
Byte = hex_chars[(*ptr >> 4) & 0xf]; Byte = hex_chars[(*ptr >> 4) & 0xf];
@ -164,7 +168,7 @@ gdb_send_debug_io(
} }
void void
gdb_send_exception(void) gdb_send_exception(BOOLEAN WithThread)
{ {
char gdb_out[1024]; char gdb_out[1024];
char* ptr = gdb_out; char* ptr = gdb_out;
@ -180,11 +184,20 @@ gdb_send_exception(void)
} }
else else
ptr += sprintf(ptr, "05"); ptr += sprintf(ptr, "05");
if (WithThread)
ptr += sprintf(ptr, "thread:p%" PRIxPTR ".%" PRIxPTR ";", {
handle_to_gdb_pid(PsGetThreadProcessId(Thread)), #if MONOPROCESS
handle_to_gdb_tid(PsGetThreadId(Thread))); ptr += sprintf(ptr, "thread:%" PRIxPTR ";",
handle_to_gdb_tid(PsGetThreadId(Thread)));
#else
ptr += sprintf(ptr, "thread:p%" PRIxPTR ".%" PRIxPTR ";",
handle_to_gdb_pid(PsGetThreadProcessId(Thread)),
handle_to_gdb_tid(PsGetThreadId(Thread)));
#endif
}
ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor); ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
/* Add program counter */
gdb_append_pc_to_exception(Thread, ptr);
send_gdb_packet(gdb_out); send_gdb_packet(gdb_out);
} }

View file

@ -93,6 +93,7 @@ thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size)
case ESP: case ESP:
case EBP: case EBP:
case EIP: case EIP:
KDDBGPRINT("Returning NULL for register %d.\n", reg_name);
*size = 4; *size = 4;
return &NullValue; return &NullValue;
default: default:
@ -143,12 +144,8 @@ thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size)
return NULL; return NULL;
} }
KDSTATUS void
gdb_send_registers( gdb_send_registers(void)
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{ {
CHAR Registers[16*8 + 1]; CHAR Registers[16*8 + 1];
UCHAR* RegisterPtr; UCHAR* RegisterPtr;
@ -184,7 +181,7 @@ gdb_send_registers(
{ {
/* Thread is dead */ /* Thread is dead */
send_gdb_packet("E03"); send_gdb_packet("E03");
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return;
} }
for(i=0; i < 16; i++) for(i=0; i < 16; i++)
@ -209,15 +206,10 @@ gdb_send_registers(
} }
*ptr = '\0'; *ptr = '\0';
send_gdb_packet(Registers); send_gdb_packet(Registers);
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
} }
KDSTATUS void
gdb_send_register( gdb_send_register(void)
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{ {
enum reg_name reg_name; enum reg_name reg_name;
void *ptr; void *ptr;
@ -242,7 +234,7 @@ gdb_send_register(
{ {
/* Thread is dead */ /* Thread is dead */
send_gdb_packet("E03"); send_gdb_packet("E03");
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); return;
} }
ptr = thread_to_reg(DbgThread, reg_name, &size); ptr = thread_to_reg(DbgThread, reg_name, &size);
@ -257,6 +249,30 @@ gdb_send_register(
{ {
send_gdb_memory(ptr, size); send_gdb_memory(ptr, size);
} }
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
} }
char*
gdb_append_pc_to_exception(
_In_ PETHREAD Thread,
_Inout_ char* ptr)
{
/* Get EIP */
unsigned short ptrSize;
unsigned char* EipPtr = thread_to_reg(Thread, EIP, &ptrSize);
/* Print it */
ptr += sprintf(ptr, "08:");
*ptr++ = hex_chars[EipPtr[0] >> 4];
*ptr++ = hex_chars[EipPtr[0] & 0xF];
*ptr++ = hex_chars[EipPtr[1] >> 4];
*ptr++ = hex_chars[EipPtr[1] & 0xF];
*ptr++ = hex_chars[EipPtr[2] >> 4];
*ptr++ = hex_chars[EipPtr[2] & 0xF];
*ptr++ = hex_chars[EipPtr[3] >> 4];
*ptr++ = hex_chars[EipPtr[3] & 0xF];
*ptr++ = ';';
*ptr++ = '\0';
return ptr;
}

View file

@ -296,15 +296,15 @@ KDSTATUS
NTAPI NTAPI
KdpReceiveByte(_Out_ PUCHAR OutByte) KdpReceiveByte(_Out_ PUCHAR OutByte)
{ {
USHORT CpStatus = CpGetByte(&KdComPort, OutByte, TRUE, FALSE);
/* Get the byte */ /* Get the byte */
if (CpGetByte(&KdComPort, OutByte, TRUE, FALSE) == CP_GET_SUCCESS) if (CpStatus == CP_GET_SUCCESS)
{ {
return KdPacketReceived; return KdPacketReceived;
} }
else
{ KDDBGPRINT("CpGetByte returned %u.\n", CpStatus);
return KdPacketTimedOut; return KdPacketTimedOut;
}
} }
KDSTATUS KDSTATUS
@ -319,6 +319,7 @@ KdpPollBreakIn(VOID)
{ {
if (Byte == 0x03) if (Byte == 0x03)
{ {
KDDBGPRINT("BreakIn Polled.\n");
return KdPacketReceived; return KdPacketReceived;
} }
else if (Byte == '$') else if (Byte == '$')

View file

@ -21,6 +21,9 @@
#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
#ifndef KDDEBUG #ifndef KDDEBUG
#define KDDBGPRINT(...) #define KDDBGPRINT(...)
#else #else
@ -34,6 +37,7 @@ FORCEINLINE HANDLE gdb_tid_to_handle(UINT_PTR Tid)
return (HANDLE)(Tid - 1); return (HANDLE)(Tid - 1);
} }
#define gdb_pid_to_handle gdb_tid_to_handle #define gdb_pid_to_handle gdb_tid_to_handle
FORCEINLINE UINT_PTR handle_to_gdb_tid(HANDLE Handle) FORCEINLINE UINT_PTR handle_to_gdb_tid(HANDLE Handle)
{ {
return (UINT_PTR)Handle + 1; return (UINT_PTR)Handle + 1;
@ -68,7 +72,6 @@ typedef KDSTATUS (*KDP_MANIPULATESTATE_HANDLER)(
/* gdb_input.c */ /* gdb_input.c */
extern UINT_PTR gdb_dbg_tid; extern UINT_PTR gdb_dbg_tid;
extern UINT_PTR gdb_dbg_pid; extern UINT_PTR gdb_dbg_pid;
extern KDSTATUS gdb_interpret_input(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
extern KDSTATUS gdb_receive_and_interpret_packet(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext); extern KDSTATUS gdb_receive_and_interpret_packet(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
/* gdb_receive.c */ /* gdb_receive.c */
@ -79,8 +82,8 @@ char hex_value(char ch);
/* gdb_send.c */ /* gdb_send.c */
void send_gdb_packet(_In_ CHAR* Buffer); void send_gdb_packet(_In_ CHAR* Buffer);
void send_gdb_memory(_In_ VOID* Buffer, size_t Length); void send_gdb_memory(_In_ VOID* Buffer, size_t Length);
void gdb_send_debug_io(_In_ PSTRING String); void gdb_send_debug_io(_In_ PSTRING String, _In_ BOOLEAN WithPrefix);
void gdb_send_exception(void); void gdb_send_exception(BOOLEAN WithThread);
void send_gdb_ntstatus(_In_ NTSTATUS Status); void send_gdb_ntstatus(_In_ NTSTATUS Status);
extern const char hex_chars[]; extern const char hex_chars[];
@ -108,8 +111,9 @@ 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 KDSTATUS gdb_send_register(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext); extern void gdb_send_register(void);
extern KDSTATUS gdb_send_registers(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext); extern void gdb_send_registers(void);
extern char* gdb_append_pc_to_exception(_In_ PETHREAD Thread, _Inout_ char* ptr);
/* 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

View file

@ -94,6 +94,7 @@ SetContextSendHandler(
|| (State->ReturnStatus != STATUS_SUCCESS)) || (State->ReturnStatus != STATUS_SUCCESS))
{ {
/* Should we bugcheck ? */ /* Should we bugcheck ? */
KDDBGPRINT("BAD BAD BAD not manipulating state for sending context.\n");
while (1); while (1);
} }
@ -116,6 +117,7 @@ SetContextManipulateHandler(
if (MessageData->MaximumLength < sizeof(CurrentContext)) if (MessageData->MaximumLength < sizeof(CurrentContext))
{ {
KDDBGPRINT("Wrong message length %u.\n", MessageData->MaximumLength);
while (1); while (1);
} }
@ -153,14 +155,18 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
PsGetThreadId(Thread)); PsGetThreadId(Thread));
/* Set the current debugged process/thread accordingly */ /* Set the current debugged process/thread accordingly */
gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread)); gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
#if MONOPROCESS
gdb_dbg_pid = 0;
#else
gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread)); gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
gdb_send_exception(); #endif
gdb_send_exception(FALSE);
/* Next receive call will ask for the context */ /* Next receive call will ask for the context */
KdpManipulateStateHandler = GetContextManipulateHandler; KdpManipulateStateHandler = GetContextManipulateHandler;
break; break;
} }
default: default:
/* FIXME */ KDDBGPRINT("Unknown StateChange %u.\n", StateChange->NewState);
while (1); while (1);
} }
} }
@ -177,10 +183,10 @@ send_kd_debug_io(
switch (DebugIO->ApiNumber) switch (DebugIO->ApiNumber)
{ {
case DbgKdPrintStringApi: case DbgKdPrintStringApi:
gdb_send_debug_io(String); gdb_send_debug_io(String, TRUE);
break; break;
default: default:
/* FIXME */ KDDBGPRINT("Unknown ApiNumber %u.\n", DebugIO->ApiNumber);
while (1); while (1);
} }
} }
@ -200,7 +206,7 @@ send_kd_state_manipulate(
return; return;
#endif #endif
default: default:
/* FIXME */ KDDBGPRINT("Unknown ApiNumber %u.\n", State->ApiNumber);
while (1); while (1);
} }
} }
@ -314,7 +320,11 @@ FirstSendHandler(
/* Set up the current state */ /* Set up the current state */
CurrentStateChange = *StateChange; CurrentStateChange = *StateChange;
gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread)); gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread));
#if MONOPROCESS
gdb_dbg_pid = 0;
#else
gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread)); gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
#endif
/* This is the idle process. Save it! */ /* This is the idle process. Save it! */
TheIdleThread = Thread; TheIdleThread = Thread;
TheIdleProcess = (PEPROCESS)Thread->Tcb.ApcState.Process; TheIdleProcess = (PEPROCESS)Thread->Tcb.ApcState.Process;
@ -352,7 +362,6 @@ KdReceivePacket(
_Out_ PULONG DataLength, _Out_ PULONG DataLength,
_Inout_ PKD_CONTEXT KdContext) _Inout_ PKD_CONTEXT KdContext)
{ {
KDSTATUS Status;
DBGKD_MANIPULATE_STATE64* State; DBGKD_MANIPULATE_STATE64* State;
/* Special handling for breakin packet */ /* Special handling for breakin packet */
@ -373,13 +382,8 @@ KdReceivePacket(
if (KdpManipulateStateHandler != NULL) if (KdpManipulateStateHandler != NULL)
return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext); return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
/* Receive data from GDB */ /* Receive data from GDB and interpret it */
Status = gdb_receive_packet(KdContext); return gdb_receive_and_interpret_packet(State, MessageData, DataLength, KdContext);
if (Status != KdPacketReceived)
return Status;
/* Interpret it */
return gdb_interpret_input(State, MessageData, DataLength, KdContext);
} }
VOID VOID
@ -409,7 +413,7 @@ KdSendPacket(
send_kd_state_manipulate((DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer, MessageData); send_kd_state_manipulate((DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer, MessageData);
break; break;
default: default:
/* FIXME */ KDDBGPRINT("Unknown packet type %u.\n", PacketType);
while (1); while (1);
} }
} }

View file

@ -21,7 +21,7 @@ find_process(
PEPROCESS Process; PEPROCESS Process;
/* Special case for idle process */ /* Special case for idle process */
if (Pid == 1) if (ProcessId == NULL)
return TheIdleProcess; return TheIdleProcess;
for (ProcessEntry = ProcessListHead->Flink; for (ProcessEntry = ProcessListHead->Flink;
@ -46,15 +46,44 @@ find_thread(
PETHREAD Thread; PETHREAD Thread;
PEPROCESS Process; PEPROCESS Process;
LIST_ENTRY* ThreadEntry; LIST_ENTRY* ThreadEntry;
#if MONOPROCESS
LIST_ENTRY* ProcessEntry;
#endif
if (
#if !MONOPROCESS
(Pid == 0) &&
#endif
(Tid == 0))
{
/* Zero means any, so use the current one */
return (PETHREAD)(ULONG_PTR)CurrentStateChange.Thread;
}
#if MONOPROCESS
/* Special case for the idle thread */ /* Special case for the idle thread */
if ((Pid == 1) && (Tid == 1)) if (Tid == 1)
return TheIdleThread; return TheIdleThread;
for (ProcessEntry = ProcessListHead->Flink;
ProcessEntry != ProcessListHead;
ProcessEntry = ProcessEntry->Flink)
{
Process = CONTAINING_RECORD(ProcessEntry, EPROCESS, ActiveProcessLinks);
#else
Process = find_process(Pid); Process = find_process(Pid);
/* Special case for the idle thread */
if ((Process == TheIdleProcess) && (Tid == 1))
return TheIdleThread;
if (!Process) if (!Process)
return NULL; return NULL;
#endif
for (ThreadEntry = Process->ThreadListHead.Flink; for (ThreadEntry = Process->ThreadListHead.Flink;
ThreadEntry != &Process->ThreadListHead; ThreadEntry != &Process->ThreadListHead;
ThreadEntry = ThreadEntry->Flink) ThreadEntry = ThreadEntry->Flink)
@ -67,5 +96,9 @@ find_thread(
} }
} }
#if MONOPROCESS
}
#endif
return NULL; return NULL;
} }

View file

@ -113,7 +113,7 @@ KdpCopyMemoryChunks(IN ULONG64 Address,
/* /*
* We may have modified executable code, flush the instruction cache * We may have modified executable code, flush the instruction cache
*/ */
KeSweepICache((PVOID)Address, TotalSize); KeSweepICache((PVOID)(ULONG_PTR)Address, TotalSize);
/* /*
* Return the size we managed to copy * Return the size we managed to copy