/* * 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"; static CHAR currentChecksum = 0; /* 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 start_gdb_packet(void) { /* Start the start byte and begin checksum calculation */ KdpSendByte('$'); currentChecksum = 0; } void 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) { const UCHAR* ptr = Buffer; ULONG Sent = Length; while(Length--) { UCHAR Byte = *ptr++; switch (Byte) { case 0x7d: case 0x23: case 0x24: case 0x2a: currentChecksum += 0x7d; KdpSendByte(0x7d); Byte ^= 0x20; Sent++; /* Fall-through */ default: currentChecksum += Byte; KdpSendByte(Byte); } } return Sent; } void 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) { CHAR gdb_out[3]; CHAR* ptr = String->Buffer; USHORT Length = String->Length; gdb_out[2] = '\0'; start_gdb_packet(); if (WithPrefix) { send_gdb_partial_packet("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); } return finish_gdb_packet(); } KDSTATUS gdb_send_exception() { char gdb_out[1024]; char* ptr = gdb_out; PETHREAD Thread = (PETHREAD)(ULONG_PTR)CurrentStateChange.Thread; /* Report to GDB */ *ptr++ = 'T'; if (CurrentStateChange.NewState == DbgKdExceptionStateChange) { EXCEPTION_RECORD64* ExceptionRecord = &CurrentStateChange.u.Exception.ExceptionRecord; ptr = exception_code_to_gdb(ExceptionRecord->ExceptionCode, ptr); } 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))); #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); return send_gdb_packet(gdb_out); } void send_gdb_ntstatus( _In_ NTSTATUS Status) { /* Just build a EXX packet and send it */ char gdb_out[4]; gdb_out[0] = 'E'; exception_code_to_gdb(Status, &gdb_out[1]); gdb_out[3] = '\0'; send_gdb_packet(gdb_out); }