mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 10:23:22 +00:00
241 lines
5.3 KiB
C
241 lines
5.3 KiB
C
/*
|
|
* 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);
|
|
}
|