diff --git a/reactos/drivers/base/kdgdb/gdb_input.c b/reactos/drivers/base/kdgdb/gdb_input.c index 1f0c027528c..c6e5ff906ef 100644 --- a/reactos/drivers/base/kdgdb/gdb_input.c +++ b/reactos/drivers/base/kdgdb/gdb_input.c @@ -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("", 21); + Sent += send_gdb_partial_binary("", 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("", 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, "", &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("", 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); diff --git a/reactos/drivers/base/kdgdb/gdb_send.c b/reactos/drivers/base/kdgdb/gdb_send.c index 94dcacb1772..4921e895968 100644 --- a/reactos/drivers/base/kdgdb/gdb_send.c +++ b/reactos/drivers/base/kdgdb/gdb_send.c @@ -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 diff --git a/reactos/drivers/base/kdgdb/i386_sup.c b/reactos/drivers/base/kdgdb/i386_sup.c index e2ee4b9555f..71ee2186290 100644 --- a/reactos/drivers/base/kdgdb/i386_sup.c +++ b/reactos/drivers/base/kdgdb/i386_sup.c @@ -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); } } diff --git a/reactos/drivers/base/kdgdb/kdgdb.h b/reactos/drivers/base/kdgdb/kdgdb.h index 243aa984e05..180320f108c 100644 --- a/reactos/drivers/base/kdgdb/kdgdb.h +++ b/reactos/drivers/base/kdgdb/kdgdb.h @@ -19,7 +19,7 @@ #include -//#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 diff --git a/reactos/drivers/base/kdgdb/kdpacket.c b/reactos/drivers/base/kdgdb/kdpacket.c index a808739bbb7..3e6474a68bc 100644 --- a/reactos/drivers/base/kdgdb/kdpacket.c +++ b/reactos/drivers/base/kdgdb/kdpacket.c @@ -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);