[KDGDB]
[reactos.git] / reactos / drivers / base / kdgdb / gdb_send.c
diff --git a/reactos/drivers/base/kdgdb/gdb_send.c b/reactos/drivers/base/kdgdb/gdb_send.c
new file mode 100644 (file)
index 0000000..4e64495
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * COPYRIGHT:       GPL, see COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            drivers/base/kddll/gdb_send.c
+ * PURPOSE:         Base functions for the kernel debugger.
+ */
+
+#include "kdgdb.h"
+
+/* LOCALS *********************************************************************/
+const char hex_chars[] = "0123456789abcdef";
+
+/* PRIVATE FUNCTIONS **********************************************************/
+static
+char*
+exception_code_to_gdb(NTSTATUS code, char* out)
+{
+    unsigned char SigVal;
+
+    switch (code)
+    {
+    case STATUS_INTEGER_DIVIDE_BY_ZERO:
+        SigVal = 8; /* divide by zero */
+        break;
+    case STATUS_SINGLE_STEP:
+    case STATUS_BREAKPOINT:
+        SigVal = 5; /* breakpoint */
+        break;
+    case STATUS_INTEGER_OVERFLOW:
+    case STATUS_ARRAY_BOUNDS_EXCEEDED:
+        SigVal = 16; /* bound instruction */
+        break;
+    case STATUS_ILLEGAL_INSTRUCTION:
+        SigVal = 4; /* Invalid opcode */
+        break;
+    case STATUS_STACK_OVERFLOW:
+    case STATUS_DATATYPE_MISALIGNMENT:
+    case STATUS_ACCESS_VIOLATION:
+        SigVal = 11; /* access violation */
+        break;
+    default:
+        SigVal = 7; /* "software generated" */
+    }
+    *out++ = hex_chars[(SigVal >> 4) & 0xf];
+    *out++ = hex_chars[SigVal & 0xf];
+    return out;
+}
+
+/* GLOBAL FUNCTIONS ***********************************************************/
+void
+send_gdb_packet(_In_ CHAR* Buffer)
+{
+    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 != '+');
+}
+
+void
+send_gdb_memory(
+    _In_ VOID* Buffer,
+    _In_ size_t Length)
+{
+    UCHAR ack;
+
+    do {
+        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(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
+gdb_send_debug_io(
+    _In_ PSTRING String)
+{
+    UCHAR ack;
+
+    do {
+        CHAR* ptr = String->Buffer;
+        CHAR check_sum;
+        USHORT Length = String->Length;
+        CHAR Byte;
+
+        KdpSendByte('$');
+
+        KdpSendByte('O');
+
+        /* Send the data */
+        check_sum = 'O';
+        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 != '+');
+}
+
+void
+gdb_send_exception(void)
+{
+    char gdb_out[1024];
+    char* ptr = gdb_out;
+    DBGKM_EXCEPTION64* Exception = NULL;
+
+    if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
+        Exception = &CurrentStateChange.u.Exception;
+
+    /* Report to GDB */
+    *ptr++ = 'T';
+    if (Exception)
+        ptr = exception_code_to_gdb(Exception->ExceptionRecord.ExceptionCode, ptr);
+    else
+        ptr += sprintf(ptr, "05");
+    ptr += sprintf(ptr, "thread:p%p.%p;",
+        PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread),
+        PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
+    ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
+    send_gdb_packet(gdb_out);
+}
+
+#ifdef KDDEBUG
+ULONG KdpDbgPrint(const char* Format, ...)
+{
+    va_list ap;
+    CHAR Buffer[512];
+    struct _STRING Str;
+    int Length;
+
+    va_start(ap, Format);
+    Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap);
+    va_end(ap);
+
+    /* Check if we went past the buffer */
+    if (Length == -1)
+    {
+        /* Terminate it if we went over-board */
+        Buffer[sizeof(Buffer) - 1] = '\n';
+
+        /* Put maximum */
+        Length = sizeof(Buffer);
+    }
+
+    Str.Buffer = Buffer;
+    Str.Length = Length;
+    Str.MaximumLength = sizeof(Buffer);
+
+    gdb_send_debug_io(&Str);
+
+    return 0;
+}
+#endif
+