mirror of
https://github.com/reactos/reactos.git
synced 2025-05-06 10:28:45 +00:00
[KDGDB]
- 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:
parent
b26a0236de
commit
9cc2b4e75c
12 changed files with 1272 additions and 4 deletions
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
29
reactos/drivers/base/kdgdb/CMakeLists.txt
Normal file
29
reactos/drivers/base/kdgdb/CMakeLists.txt
Normal 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)
|
285
reactos/drivers/base/kdgdb/gdb_input.c
Normal file
285
reactos/drivers/base/kdgdb/gdb_input.c
Normal 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);
|
||||
}
|
90
reactos/drivers/base/kdgdb/gdb_receive.c
Normal file
90
reactos/drivers/base/kdgdb/gdb_receive.c
Normal 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;
|
||||
}
|
220
reactos/drivers/base/kdgdb/gdb_send.c
Normal file
220
reactos/drivers/base/kdgdb/gdb_send.c
Normal 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
|
||||
|
99
reactos/drivers/base/kdgdb/i386_sup.c
Normal file
99
reactos/drivers/base/kdgdb/i386_sup.c
Normal 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));
|
||||
}
|
269
reactos/drivers/base/kdgdb/kdcom.c
Normal file
269
reactos/drivers/base/kdgdb/kdcom.c
Normal 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 */
|
56
reactos/drivers/base/kdgdb/kdgdb.h
Normal file
56
reactos/drivers/base/kdgdb/kdgdb.h
Normal 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_ */
|
5
reactos/drivers/base/kdgdb/kdgdb.rc
Normal file
5
reactos/drivers/base/kdgdb/kdgdb.rc
Normal 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>
|
8
reactos/drivers/base/kdgdb/kdgdb.spec
Normal file
8
reactos/drivers/base/kdgdb/kdgdb.spec
Normal 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)
|
203
reactos/drivers/base/kdgdb/kdpacket.c
Normal file
203
reactos/drivers/base/kdgdb/kdpacket.c
Normal 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 */
|
Loading…
Reference in a new issue