- introduce KDGDB, a KDCOM-like DLL, wrapping the KD protocol and the GDB remote protocol together.
It is not fully functional, but for now it permits source-level debugging in some modules. More will be added as I feel the need and find the time to work a bit more on it. (That is, unless an angel comes and resume the work)
To use it, set GDB and _WINKD_ to TRUE in your CMakeCache.txt. Using separate debug symbols is also a good idea.

svn path=/trunk/; revision=64121
This commit is contained in:
Jérôme Gardou 2014-09-11 20:55:42 +00:00
parent b26a0236de
commit 9cc2b4e75c
12 changed files with 1272 additions and 4 deletions

View file

@ -62,13 +62,13 @@ set(REACTOS_SOURCE_DIR_NATIVE ${REACTOS_SOURCE_DIR})
string(REPLACE "/" "\\" REACTOS_SOURCE_DIR_NATIVE ${REACTOS_SOURCE_DIR})
endif()
if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
if((NOT CMAKE_C_COMPILER_ID STREQUAL "Clang") AND (NOT SEPARATE_DBG))
add_compile_flags("-fdebug-prefix-map=\"${REACTOS_SOURCE_DIR_NATIVE}\"=ReactOS")
endif()
# Debugging
if(SEPARATE_DBG)
add_compile_flags("-gdwarf-2 -g2")
add_compile_flags("-gdwarf-4 -fvar-tracking-assignments")
else()
add_compile_flags("-gdwarf-2 -gstrict-dwarf")
if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")

View file

@ -4,9 +4,13 @@ add_subdirectory(bootvid)
add_subdirectory(condrv)
if(_WINKD_)
add_subdirectory(kdcom)
if (GDB)
add_subdirectory(kdgdb)
else()
add_subdirectory(kdcom)
endif()
else()
add_subdirectory(kdrosdbg)
add_subdirectory(kdrosdbg)
endif()
add_subdirectory(nmidebug)

View file

@ -0,0 +1,29 @@
spec2def(kdcom.dll kdgdb.spec ADD_IMPORTLIB)
list(APPEND SOURCE
gdb_input.c
gdb_receive.c
gdb_send.c
kdcom.c
kdpacket.c
kdgdb.h)
# TODO: AMD64, ARM...
if(ARCH STREQUAL "i386")
list(APPEND SOURCE i386_sup.c)
endif()
add_library(kdcom SHARED
${SOURCE}
kdgdb.rc
${CMAKE_CURRENT_BINARY_DIR}/kdcom.def)
set_entrypoint(kdcom 0)
set_subsystem(kdcom native)
set_image_base(kdcom 0x00010000)
add_importlibs(kdcom ntoskrnl hal)
target_link_libraries(kdcom cportlib)
add_pch(kdcom kdgdb.h SOURCE)
add_cd_file(TARGET kdcom DESTINATION reactos/system32 NO_CAB FOR all)

View file

@ -0,0 +1,285 @@
/*
* COPYRIGHT: GPL, see COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/base/kddll/gdb_input.c
* PURPOSE: Base functions for the kernel debugger.
*/
#include "kdgdb.h"
/* LOCALS *********************************************************************/
static HANDLE gdb_run_thread;
static HANDLE gdb_dbg_process;
HANDLE gdb_dbg_thread;
/* PRIVATE FUNCTIONS **********************************************************/
static
HANDLE
hex_to_thread(char* buffer)
{
ULONG_PTR ret = 0;
char hex;
while (*buffer)
{
hex = hex_value(*buffer++);
if (hex < 0)
return (HANDLE)ret;
ret <<= 4;
ret += hex;
}
return (HANDLE)ret;
}
static
ULONG64
hex_to_address(char* buffer)
{
ULONG64 ret = 0;
char hex;
while (*buffer)
{
hex = hex_value(*buffer++);
if (hex < 0)
return ret;
ret <<= 4;
ret += hex;
}
return ret;
}
/* H* packets */
static
void
handle_gdb_set_thread(void)
{
switch (gdb_input[1])
{
case 'c':
if (strcmp(&gdb_input[2], "-1") == 0)
gdb_run_thread = (HANDLE)-1;
else
gdb_run_thread = hex_to_thread(&gdb_input[2]);
send_gdb_packet("OK");
break;
case 'g':
if (strncmp(&gdb_input[2], "p-1", 3) == 0)
{
gdb_dbg_process = (HANDLE)-1;
gdb_dbg_thread = (HANDLE)-1;
}
else
{
char* ptr = strstr(gdb_input, ".") + 1;
gdb_dbg_process = hex_to_thread(&gdb_input[3]);
if (strncmp(ptr, "-1", 2) == 0)
gdb_dbg_thread = (HANDLE)-1;
else
gdb_dbg_thread = hex_to_thread(ptr);
}
send_gdb_packet("OK");
break;
default:
KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input);
send_gdb_packet("");
}
}
static
void
handle_gdb_thread_alive(void)
{
char* ptr = strstr(gdb_input, ".") + 1;
CLIENT_ID ClientId;
PETHREAD Thread;
NTSTATUS Status;
ClientId.UniqueProcess = hex_to_thread(&gdb_input[2]);
ClientId.UniqueThread = hex_to_thread(ptr);
Status = PsLookupProcessThreadByCid(&ClientId, NULL, &Thread);
if (!NT_SUCCESS(Status))
{
/* Thread doesn't exist */
send_gdb_packet("E03");
return;
}
/* It's OK */
ObDereferenceObject(Thread);
send_gdb_packet("OK");
}
/* q* packets */
static
void
handle_gdb_query(void)
{
if (strncmp(gdb_input, "qSupported:", 11) == 0)
{
send_gdb_packet("PacketSize=4096;multiprocess+;");
return;
}
if (strncmp(gdb_input, "qAttached", 9) == 0)
{
/* Say yes: the remote server didn't create the process, ReactOS did! */
send_gdb_packet("0");
return;
}
if (strncmp(gdb_input, "qRcmd,", 6) == 0)
{
send_gdb_packet("OK");
return;
}
if (strcmp(gdb_input, "qC") == 0)
{
char gdb_out[64];
sprintf(gdb_out, "QC:p%p.%p;",
PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread),
PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
send_gdb_packet(gdb_out);
return;
}
if (strncmp(gdb_input, "qTStatus", 8) == 0)
{
/* We don't support tracepoints. */
send_gdb_packet("T0");
return;
}
KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input);
send_gdb_packet("");
}
#if 0
static
KDSTATUS
handle_gdb_registers(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength)
{
/*
if (gdb_dbg_thread)
KDDBGPRINT("Should get registers from other thread!\n");
*/
State->ApiNumber = DbgKdGetContextApi;
State->ReturnStatus = STATUS_SUCCESS; /* ? */
State->Processor = CurrentStateChange.Processor;
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
if (MessageData)
MessageData->Length = 0;
*MessageLength = 0;
return KdPacketReceived;
}
#endif
static
KDSTATUS
handle_gdb_read_mem(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength)
{
State->ApiNumber = DbgKdReadVirtualMemoryApi;
State->ReturnStatus = STATUS_SUCCESS; /* ? */
State->Processor = CurrentStateChange.Processor;
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
if (MessageData)
MessageData->Length = 0;
*MessageLength = 0;
State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
return KdPacketReceived;
}
static
KDSTATUS
handle_gdb_v(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{
if (strncmp(gdb_input, "vCont", 5) == 0)
{
if (gdb_input[5] == '?')
{
KDSTATUS Status;
/* Report what we support */
send_gdb_packet("vCont;c;C;s;S");
Status = gdb_receive_packet(KdContext);
if (Status != KdPacketReceived)
return Status;
return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
}
if (strcmp(gdb_input, "vCont;c") == 0)
{
/* Let's go on */
State->ApiNumber = DbgKdContinueApi;
State->ReturnStatus = STATUS_SUCCESS; /* ? */
State->Processor = CurrentStateChange.Processor;
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
if (MessageData)
MessageData->Length = 0;
*MessageLength = 0;
State->u.Continue.ContinueStatus = STATUS_SUCCESS;
/* Tell GDB we are fine */
send_gdb_packet("OK");
return KdPacketReceived;
}
}
return KdPacketReceived;
}
/* GLOBAL FUNCTIONS ***********************************************************/
KDSTATUS
gdb_interpret_input(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{
KDSTATUS Status;
switch (gdb_input[0])
{
case '?':
/* Send the Status */
gdb_send_exception();
break;
case 'g':
gdb_send_registers();
break;
case 'H':
handle_gdb_set_thread();
break;
case 'm':
return handle_gdb_read_mem(State, MessageData, MessageLength);
case 'q':
handle_gdb_query();
break;
case 'T':
handle_gdb_thread_alive();
break;
case 'v':
return handle_gdb_v(State, MessageData, MessageLength, KdContext);
default:
/* We don't know how to handle this request. Maybe this is something for KD */
State->ReturnStatus = STATUS_NOT_SUPPORTED;
return KdPacketReceived;
}
/* Get the answer from GDB */
Status = gdb_receive_packet(KdContext);
if (Status != KdPacketReceived)
return Status;
/* Try interpreting this new packet */
return gdb_interpret_input(State, MessageData, MessageLength, KdContext);
}

View file

@ -0,0 +1,90 @@
/*
* COPYRIGHT: GPL, see COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/base/kddll/gdb_receive.c
* PURPOSE: Base functions for the kernel debugger.
*/
#include "kdgdb.h"
/* GLOBALS ********************************************************************/
CHAR gdb_input[0x1000];
/* GLOBAL FUNCTIONS ***********************************************************/
char
hex_value(char ch)
{
if ((ch >= '0') && (ch <= '9'))
return (ch - '0');
if ((ch >= 'a') && (ch <= 'f'))
return (ch - 'a' + 10);
if ((ch >= 'A') && (ch <= 'F'))
return (ch - 'A' + 10);
return -1;
}
KDSTATUS
NTAPI
gdb_receive_packet(_Inout_ PKD_CONTEXT KdContext)
{
char* ByteBuffer = gdb_input;
UCHAR Byte;
KDSTATUS Status;
CHAR CheckSum = 0, ReceivedCheckSum;
do
{
Status = KdpReceiveByte(&Byte);
if (Status != KdPacketReceived)
return Status;
if (Byte == 0x03)
{
KdContext->KdpControlCPending = TRUE;
return KdPacketNeedsResend;
}
} while (Byte != '$');
while (TRUE)
{
/* Try to get a byte from the port */
Status = KdpReceiveByte(&Byte);
if (Status != KdPacketReceived)
return Status;
if (Byte == '#')
{
*ByteBuffer = '\0';
break;
}
*ByteBuffer++ = Byte;
CheckSum += (CHAR)Byte;
}
/* Get Check sum (two bytes) */
Status = KdpReceiveByte(&Byte);
if (Status != KdPacketReceived)
goto end;
ReceivedCheckSum = hex_value(Byte) << 4;;
Status = KdpReceiveByte(&Byte);
if (Status != KdPacketReceived)
goto end;
ReceivedCheckSum += hex_value(Byte);
end:
if (ReceivedCheckSum != CheckSum)
{
/* Do not acknowledge to GDB */
KdpSendByte('-');
return KdPacketNeedsResend;
}
/* Acknowledge */
KdpSendByte('+');
return KdPacketReceived;
}

View file

@ -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

View file

@ -0,0 +1,99 @@
/*
* COPYRIGHT: GPL, see COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/base/kddll/gdb_input.c
* PURPOSE: Base functions for the kernel debugger.
*/
#include "kdgdb.h"
enum reg_name
{
EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
EIP,
EFLAGS,
CS, SS, DS, ES, FS, GS,
ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7,
FCTRL, FSTAT, FTAG, FISEG, FIOFF, FOSEG, FOOFF, FOP,
XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
MXCSR
};
static
void*
ctx_to_reg(CONTEXT* ctx, enum reg_name name, unsigned short* size)
{
/* For general registers: 32bits */
*size = 4;
switch (name)
{
case EAX: return &ctx->Eax;
case EBX: return &ctx->Ebx;
case ECX: return &ctx->Ecx;
case EDX: return &ctx->Edx;
case ESP: return &ctx->Esp;
case EBP: return &ctx->Ebp;
case ESI: return &ctx->Esi;
case EDI: return &ctx->Edi;
case EIP: return &ctx->Eip;
case EFLAGS: return &ctx->EFlags;
case CS: return &ctx->SegCs;
case DS: return &ctx->SegDs;
case ES: return &ctx->SegEs;
case FS: return &ctx->SegFs;
case GS: return &ctx->SegGs;
case SS: return &ctx->SegSs;
/* 80 bits */
case ST0:
case ST1:
case ST2:
case ST3:
case ST4:
case ST5:
case ST6:
case ST7:
*size = 10;
return &ctx->FloatSave.RegisterArea[10 * (name - ST0)];
/* X87 registers */
case FCTRL: return &ctx->FloatSave.ControlWord;
case FSTAT: return &ctx->FloatSave.StatusWord;
case FTAG: return &ctx->FloatSave.TagWord;
case FISEG: return &ctx->FloatSave.DataSelector;
case FIOFF: return &ctx->FloatSave.DataOffset;
case FOSEG: return &ctx->FloatSave.ErrorSelector;
case FOOFF: return &ctx->FloatSave.ErrorOffset;
case FOP: return &ctx->FloatSave.Cr0NpxState;
/* SSE */
case XMM0:
case XMM1:
case XMM2:
case XMM3:
case XMM4:
case XMM5:
case XMM6:
case XMM7:
*size = 16;
return &ctx->ExtendedRegisters[160 + (name - XMM0)*16];
case MXCSR: return &ctx->ExtendedRegisters[24];
}
return 0;
}
void
gdb_send_registers(void)
{
CONTEXT* ctx;
PKPRCB* ProcessorBlockLists;
ULONG32 Registers[16];
unsigned i;
unsigned short size;
ProcessorBlockLists = (PKPRCB*)KdDebuggerDataBlock->KiProcessorBlock.Pointer;
ctx = (CONTEXT*)((char*)ProcessorBlockLists[CurrentStateChange.Processor] + KdDebuggerDataBlock->OffsetPrcbProcStateContext);
for(i=0; i < 16; i++)
{
Registers[i] = *(ULONG32*)ctx_to_reg(ctx, i, &size);
}
send_gdb_memory(Registers, sizeof(Registers));
}

View file

@ -0,0 +1,269 @@
/*
* COPYRIGHT: GPL, see COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/base/kdgdb/kdcom.c
* PURPOSE: COM port functions for the kernel debugger.
*/
#include "kdgdb.h"
#include <cportlib/cportlib.h>
#include <arc/arc.h>
#include <stdlib.h>
#include <ndk/halfuncs.h>
/* Serial debug connection */
#define DEFAULT_DEBUG_PORT 2 /* COM2 */
#define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */
#define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */
#define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */
#define DEFAULT_BAUD_RATE 19200
#if defined(_M_IX86) || defined(_M_AMD64)
const ULONG BaseArray[] = {0, 0x3F8, 0x2F8, 0x3E8, 0x2E8};
#elif defined(_M_PPC)
const ULONG BaseArray[] = {0, 0x800003F8};
#elif defined(_M_MIPS)
const ULONG BaseArray[] = {0, 0x80006000, 0x80007000};
#elif defined(_M_ARM)
const ULONG BaseArray[] = {0, 0xF1012000};
#else
#error Unknown architecture
#endif
/* GLOBALS ********************************************************************/
CPPORT KdDebugComPort;
ULONG KdDebugComPortIrq = 0; // Not used at the moment.
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
KdD0Transition(VOID)
{
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
KdD3Transition(VOID)
{
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
KdSave(IN BOOLEAN SleepTransition)
{
/* Nothing to do on COM ports */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
KdRestore(IN BOOLEAN SleepTransition)
{
/* Nothing to do on COM ports */
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
KdpPortInitialize(IN ULONG ComPortNumber,
IN ULONG ComPortBaudRate)
{
NTSTATUS Status;
Status = CpInitialize(&KdDebugComPort,
UlongToPtr(BaseArray[ComPortNumber]),
ComPortBaudRate);
if (!NT_SUCCESS(Status))
{
return STATUS_INVALID_PARAMETER;
}
else
{
KdComPortInUse = KdDebugComPort.Address;
return STATUS_SUCCESS;
}
}
/******************************************************************************
* \name KdDebuggerInitialize0
* \brief Phase 0 initialization.
* \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
* \return Status
*/
NTSTATUS
NTAPI
KdDebuggerInitialize0(IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
{
ULONG ComPortNumber = DEFAULT_DEBUG_PORT;
ULONG ComPortBaudRate = DEFAULT_DEBUG_BAUD_RATE;
PCHAR CommandLine, PortString, BaudString, IrqString;
ULONG Value;
/* Check if e have a LoaderBlock */
if (LoaderBlock)
{
/* Get the Command Line */
CommandLine = LoaderBlock->LoadOptions;
/* Upcase it */
_strupr(CommandLine);
/* Get the port and baud rate */
PortString = strstr(CommandLine, "DEBUGPORT");
BaudString = strstr(CommandLine, "BAUDRATE");
IrqString = strstr(CommandLine, "IRQ");
/* Check if we got the /DEBUGPORT parameter */
if (PortString)
{
/* Move past the actual string, to reach the port*/
PortString += strlen("DEBUGPORT");
/* Now get past any spaces and skip the equal sign */
while (*PortString == ' ') PortString++;
PortString++;
/* Do we have a serial port? */
if (strncmp(PortString, "COM", 3) != 0)
{
return STATUS_INVALID_PARAMETER;
}
/* Check for a valid Serial Port */
PortString += 3;
Value = atol(PortString);
if (Value >= sizeof(BaseArray) / sizeof(BaseArray[0]))
{
return STATUS_INVALID_PARAMETER;
}
/* Set the port to use */
ComPortNumber = Value;
}
/* Check if we got a baud rate */
if (BaudString)
{
/* Move past the actual string, to reach the rate */
BaudString += strlen("BAUDRATE");
/* Now get past any spaces */
while (*BaudString == ' ') BaudString++;
/* And make sure we have a rate */
if (*BaudString)
{
/* Read and set it */
Value = atol(BaudString + 1);
if (Value) ComPortBaudRate = Value;
}
}
/* Check Serial Port Settings [IRQ] */
if (IrqString)
{
/* Move past the actual string, to reach the rate */
IrqString += strlen("IRQ");
/* Now get past any spaces */
while (*IrqString == ' ') IrqString++;
/* And make sure we have an IRQ */
if (*IrqString)
{
/* Read and set it */
Value = atol(IrqString + 1);
if (Value) KdDebugComPortIrq = Value;
}
}
}
/* Initialize the port */
return KdpPortInitialize(ComPortNumber, ComPortBaudRate);
}
/******************************************************************************
* \name KdDebuggerInitialize1
* \brief Phase 1 initialization.
* \param [opt] LoaderBlock Pointer to the Loader parameter block. Can be NULL.
* \return Status
*/
NTSTATUS
NTAPI
KdDebuggerInitialize1(IN PLOADER_PARAMETER_BLOCK LoaderBlock OPTIONAL)
{
return STATUS_SUCCESS;
}
VOID
NTAPI
KdpSendByte(_In_ UCHAR Byte)
{
/* Send the byte */
CpPutByte(&KdDebugComPort, Byte);
}
KDSTATUS
NTAPI
KdpPollByte(OUT PUCHAR OutByte)
{
/* Poll the byte */
if (CpGetByte(&KdDebugComPort, OutByte, FALSE, FALSE) == CP_GET_SUCCESS)
{
return KdPacketReceived;
}
else
{
return KdPacketTimedOut;
}
}
KDSTATUS
NTAPI
KdpReceiveByte(_Out_ PUCHAR OutByte)
{
/* Get the byte */
if (CpGetByte(&KdDebugComPort, OutByte, TRUE, FALSE) == CP_GET_SUCCESS)
{
return KdPacketReceived;
}
else
{
return KdPacketTimedOut;
}
}
KDSTATUS
NTAPI
KdpPollBreakIn(VOID)
{
KDSTATUS KdStatus;
UCHAR Byte;
KdStatus = KdpPollByte(&Byte);
if (KdStatus == KdPacketReceived)
{
if (Byte == 0x03)
{
return KdPacketReceived;
}
else if (Byte == '$')
{
/* GDB tried to send a new packet. N-ack it. */
KdpSendByte('-');
}
}
return KdPacketTimedOut;
}
/* EOF */

View file

@ -0,0 +1,56 @@
/*
* COPYRIGHT: GPL, see COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/base/kddll/kddll.h
* PURPOSE: Base definitions for the kernel debugger.
*/
#ifndef _KDGDB_H_
#define _KDGDB_H_
#define NOEXTAPI
#include <ntifs.h>
#include <halfuncs.h>
#include <stdio.h>
#include <arc/arc.h>
#include <windbgkd.h>
#include <kddll.h>
// #define KDDEBUG /* uncomment to enable debugging this dll */
#ifndef KDDEBUG
#define KDDBGPRINT(...)
#else
extern ULONG KdpDbgPrint(const char* Format, ...);
#define KDDBGPRINT KdpDbgPrint
#endif
/* gdb_input.c */
extern HANDLE gdb_dbg_thread;
KDSTATUS gdb_interpret_input(_Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext);
/* gdb_receive.c */
extern CHAR gdb_input[];
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);
void gdb_send_exception(void);
/* kdcom.c */
KDSTATUS NTAPI KdpPollBreakIn(VOID);
VOID NTAPI KdpSendByte(_In_ UCHAR Byte);
KDSTATUS NTAPI KdpReceiveByte(_Out_ PUCHAR OutByte);
/* kdpacket.c */
extern DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
extern DBGKD_GET_VERSION64 KdVersion;
extern KDDEBUGGER_DATA64* KdDebuggerDataBlock;
/* arch_sup.c */
void gdb_send_registers(void);
#endif /* _KDGDB_H_ */

View file

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS GDB KDCOM wrapper DLL"
#define REACTOS_STR_INTERNAL_NAME "kdcom"
#define REACTOS_STR_ORIGINAL_FILENAME "kdcom.dll"
#include <reactos/version.rc>

View file

@ -0,0 +1,8 @@
@ stdcall KdD0Transition()
@ stdcall KdD3Transition()
@ stdcall KdDebuggerInitialize0(ptr)
@ stdcall KdDebuggerInitialize1(ptr)
@ stdcall KdReceivePacket(long ptr ptr ptr ptr)
@ stdcall KdRestore(long)
@ stdcall KdSave(long)
@ stdcall KdSendPacket(long ptr ptr ptr)

View file

@ -0,0 +1,203 @@
/*
* COPYRIGHT: GPL, see COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/base/kddll/kdpacket.c
* PURPOSE: Base functions for the kernel debugger.
*/
#include "kdgdb.h"
/* GLOBALS ********************************************************************/
DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
DBGKD_GET_VERSION64 KdVersion;
KDDEBUGGER_DATA64* KdDebuggerDataBlock;
/* LOCALS *********************************************************************/
static BOOLEAN FakeNextManipulatePacket = FALSE;
static DBGKD_MANIPULATE_STATE64 FakeManipulateState = {0};
/* PRIVATE FUNCTIONS **********************************************************/
static
void
send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
{
static BOOLEAN first = TRUE;
/* Save current state for later GDB queries */
CurrentStateChange = *StateChange;
if (first)
{
/*
* This is the first packet we receive.
* We take this as an opportunity to connect with GDB and to
* get the KD version block
*/
FakeNextManipulatePacket = TRUE;
FakeManipulateState.ApiNumber = DbgKdGetVersionApi;
FakeManipulateState.Processor = StateChange->Processor;
FakeManipulateState.ProcessorLevel = StateChange->ProcessorLevel;
FakeManipulateState.ReturnStatus = STATUS_SUCCESS;
first = FALSE;
return;
}
switch (StateChange->NewState)
{
case DbgKdLoadSymbolsStateChange:
{
/* We don't care about symbols loading */
FakeNextManipulatePacket = TRUE;
FakeManipulateState.ApiNumber = DbgKdContinueApi;
FakeManipulateState.Processor = StateChange->Processor;
FakeManipulateState.ProcessorLevel = StateChange->ProcessorLevel;
FakeManipulateState.ReturnStatus = STATUS_SUCCESS;
FakeManipulateState.u.Continue.ContinueStatus = STATUS_SUCCESS;
break;
}
case DbgKdExceptionStateChange:
gdb_send_exception();
break;
default:
/* FIXME */
while (1);
}
}
static
void
send_kd_debug_io(
_In_ DBGKD_DEBUG_IO* DebugIO,
_In_ PSTRING String)
{
switch (DebugIO->ApiNumber)
{
case DbgKdPrintStringApi:
gdb_send_debug_io(String);
break;
default:
/* FIXME */
while (1);
}
}
static
void
send_kd_state_manipulate(
_In_ DBGKD_MANIPULATE_STATE64* State,
_In_ PSTRING MessageData)
{
switch (State->ApiNumber)
{
#if 0
case DbgKdGetContextApi:
/* This is an answer to a 'g' GDB request */
gdb_send_registers((CONTEXT*)MessageData->Buffer);
return;
#endif
case DbgKdReadVirtualMemoryApi:
/* Answer to 'm' GDB request */
send_gdb_memory(MessageData->Buffer, State->u.ReadMemory.ActualBytesRead);
break;
case DbgKdGetVersionApi:
{
LIST_ENTRY* DebuggerDataList;
/* Simply get a copy */
RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion));
DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList;
KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List);
return;
}
default:
/* FIXME */
while (1);
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
/******************************************************************************
* \name KdReceivePacket
* \brief Receive a packet from the KD port.
* \param [in] PacketType Describes the type of the packet to receive.
* This can be one of the PACKET_TYPE_ constants.
* \param [out] MessageHeader Pointer to a STRING structure for the header.
* \param [out] MessageData Pointer to a STRING structure for the data.
* \return KdPacketReceived if successful, KdPacketTimedOut if the receive
* timed out, KdPacketNeedsResend to signal that the last packet needs
* to be sent again.
* \note If PacketType is PACKET_TYPE_KD_POLL_BREAKIN, the function doesn't
* wait for any data, but returns KdPacketTimedOut instantly if no breakin
* packet byte is received.
* \sa http://www.nynaeve.net/?p=169
*/
KDSTATUS
NTAPI
KdReceivePacket(
_In_ ULONG PacketType,
_Out_ PSTRING MessageHeader,
_Out_ PSTRING MessageData,
_Out_ PULONG DataLength,
_Inout_ PKD_CONTEXT KdContext)
{
KDSTATUS Status;
DBGKD_MANIPULATE_STATE64* State;
/* Special handling for breakin packet */
if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
{
return KdpPollBreakIn();
}
if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
{
/* What should we do ? */
while (1);
}
State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
if (FakeNextManipulatePacket)
{
FakeNextManipulatePacket = FALSE;
*State = FakeManipulateState;
return KdPacketReceived;
}
/* Receive data from GDB */
Status = gdb_receive_packet(KdContext);
if (Status != KdPacketReceived)
return Status;
/* Interpret it */
return gdb_interpret_input(State, MessageData, DataLength, KdContext);
}
VOID
NTAPI
KdSendPacket(
IN ULONG PacketType,
IN PSTRING MessageHeader,
IN PSTRING MessageData,
IN OUT PKD_CONTEXT KdContext)
{
switch (PacketType)
{
case PACKET_TYPE_KD_STATE_CHANGE64:
send_kd_state_change((DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer);
return;
case PACKET_TYPE_KD_DEBUG_IO:
send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
break;
case PACKET_TYPE_KD_STATE_MANIPULATE:
send_kd_state_manipulate((DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer, MessageData);
break;
default:
/* FIXME */
while (1);
}
}
/* EOF */