mirror of
https://github.com/reactos/reactos.git
synced 2025-02-25 01:39:30 +00:00
[KDGDB]
- Implement setting and removing breakpoints - Implement single-stepping - Only get past the breakpoint instruction when it comes from RtlpBreakWithStatus - Implement writing to memory - Always send the thread raising the exception to GDB to avoid confusing it - Let GDB find the program counter alone by querying the registers (support was already there before.) - Properly escape special characters on input Ladies and gentlemen : the almost-fully functional GDB stub. (still no real multi-process support :-( ) To enable , in CMakeCache.txt : - Set GDB:BOOL=TRUE - Set _WINKD_:BOOL=TRUE - Set KDBG:BOOL=FALSE To do : give GDB the list of loaded drivers. Loading ntoskrnl.exe symbols at 0x80801000 already does a good enough job. Default output is on COM1. Can be configure to any othe COM port with usual kernel options. Hope you'll like it as much as I do ;-) svn path=/trunk/; revision=72435
This commit is contained in:
parent
e41a81db0b
commit
fa5fed4f1d
7 changed files with 483 additions and 86 deletions
|
@ -9,6 +9,11 @@
|
|||
|
||||
/* LOCALS *********************************************************************/
|
||||
static ULONG_PTR gdb_run_tid;
|
||||
static struct
|
||||
{
|
||||
ULONG_PTR Address;
|
||||
ULONG Handle;
|
||||
} BreakPointHandles[32];
|
||||
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
@ -203,16 +208,15 @@ handle_gdb_query(void)
|
|||
|
||||
if (!Resuming)
|
||||
{
|
||||
/* Report the idle thread */
|
||||
#if MONOPROCESS
|
||||
ptr += sprintf(ptr, "1");
|
||||
#else
|
||||
ptr += sprintf(gdb, "p1.1");
|
||||
#endif
|
||||
/* Initialize the entries */
|
||||
CurrentProcessEntry = ProcessListHead->Flink;
|
||||
CurrentThreadEntry = NULL;
|
||||
|
||||
/* Start with idle thread */
|
||||
#if MONOPROCESS
|
||||
ptr = gdb_out + sprintf(gdb_out, "m1");
|
||||
#else
|
||||
ptr = gdb_out + sprintf(gdb_out, "mp1.1");
|
||||
#endif
|
||||
FirstThread = FALSE;
|
||||
}
|
||||
|
||||
|
@ -306,8 +310,8 @@ handle_gdb_query(void)
|
|||
Thread = find_thread(Pid, Tid);
|
||||
Process = CONTAINING_RECORD(Thread->Tcb.Process, EPROCESS, Pcb);
|
||||
#else
|
||||
Pid = hex_to_pid(&gdb_input[2]);
|
||||
Tid = hex_to_tid(strstr(gdb_input, ".") + 1);
|
||||
Pid = hex_to_pid(&gdb_input[18]);
|
||||
Tid = hex_to_tid(strstr(&gdb_input[18], ".") + 1);
|
||||
|
||||
/* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL.
|
||||
* So loop. */
|
||||
|
@ -394,21 +398,23 @@ ReadMemorySendHandler(
|
|||
KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State->ApiNumber);
|
||||
}
|
||||
|
||||
/* Check status */
|
||||
if (!NT_SUCCESS(State->ReturnStatus))
|
||||
/* Check status. Allow to send partial data. */
|
||||
if (!MessageData->Length && !NT_SUCCESS(State->ReturnStatus))
|
||||
send_gdb_ntstatus(State->ReturnStatus);
|
||||
else
|
||||
send_gdb_memory(MessageData->Buffer, MessageData->Length);
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
|
||||
#if !MONOPROCESS
|
||||
#if MONOPROCESS
|
||||
if (gdb_dbg_tid != 0)
|
||||
/* Reset the TLB */
|
||||
#else
|
||||
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
|
||||
#endif
|
||||
{
|
||||
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -427,8 +433,29 @@ handle_gdb_read_mem(
|
|||
MessageData->Length = 0;
|
||||
*MessageLength = 0;
|
||||
|
||||
#if !MONOPROCESS
|
||||
/* Set the TLB according to the process being read. Pid 0 means any process. */
|
||||
#if MONOPROCESS
|
||||
if ((gdb_dbg_tid != 0) && gdb_tid_to_handle(gdb_dbg_tid) != PsGetCurrentThreadId())
|
||||
{
|
||||
PETHREAD AttachedThread = find_thread(0, gdb_dbg_tid);
|
||||
PKPROCESS AttachedProcess;
|
||||
if (AttachedThread == NULL)
|
||||
{
|
||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||
send_gdb_packet("E03");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
|
||||
AttachedProcess = AttachedThread->Tcb.Process;
|
||||
if (AttachedProcess == NULL)
|
||||
{
|
||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||
send_gdb_packet("E03");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
__writecr3(AttachedProcess->DirectoryTableBase[0]);
|
||||
}
|
||||
#else
|
||||
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
|
||||
{
|
||||
PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
|
||||
|
@ -436,7 +463,7 @@ handle_gdb_read_mem(
|
|||
{
|
||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||
send_gdb_packet("E03");
|
||||
return gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext);
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
|
||||
}
|
||||
|
@ -451,6 +478,388 @@ handle_gdb_read_mem(
|
|||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
WriteMemorySendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData)
|
||||
{
|
||||
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
||||
|
||||
if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
||||
{
|
||||
// KdAssert
|
||||
KDDBGPRINT("Wrong packet type (%lu) received after DbgKdWriteVirtualMemoryApi request.\n", PacketType);
|
||||
while (1);
|
||||
}
|
||||
|
||||
if (State->ApiNumber != DbgKdWriteVirtualMemoryApi)
|
||||
{
|
||||
KDDBGPRINT("Wrong API number (%lu) after DbgKdWriteVirtualMemoryApi request.\n", State->ApiNumber);
|
||||
}
|
||||
|
||||
/* Check status */
|
||||
if (!NT_SUCCESS(State->ReturnStatus))
|
||||
send_gdb_ntstatus(State->ReturnStatus);
|
||||
else
|
||||
send_gdb_packet("OK");
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
|
||||
#if MONOPROCESS
|
||||
if (gdb_dbg_tid != 0)
|
||||
/* Reset the TLB */
|
||||
#else
|
||||
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
|
||||
#endif
|
||||
{
|
||||
__writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
handle_gdb_write_mem(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
/* Maximal input buffer is 0x1000. Each byte is encoded on two bytes by GDB */
|
||||
static UCHAR OutBuffer[0x800];
|
||||
ULONG BufferLength;
|
||||
char* blob_ptr;
|
||||
UCHAR* OutPtr;
|
||||
|
||||
State->ApiNumber = DbgKdWriteVirtualMemoryApi;
|
||||
State->ReturnStatus = STATUS_SUCCESS; /* ? */
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
|
||||
/* Set the TLB according to the process being read. Pid 0 means any process. */
|
||||
#if MONOPROCESS
|
||||
if ((gdb_dbg_tid != 0) && gdb_tid_to_handle(gdb_dbg_tid) != PsGetCurrentThreadId())
|
||||
{
|
||||
PETHREAD AttachedThread = find_thread(0, gdb_dbg_tid);
|
||||
PKPROCESS AttachedProcess;
|
||||
if (AttachedThread == NULL)
|
||||
{
|
||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||
send_gdb_packet("E03");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
|
||||
AttachedProcess = AttachedThread->Tcb.Process;
|
||||
if (AttachedProcess == NULL)
|
||||
{
|
||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||
send_gdb_packet("E03");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
__writecr3(AttachedProcess->DirectoryTableBase[0]);
|
||||
}
|
||||
#else
|
||||
if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())
|
||||
{
|
||||
PEPROCESS AttachedProcess = find_process(gdb_dbg_pid);
|
||||
if (AttachedProcess == NULL)
|
||||
{
|
||||
KDDBGPRINT("The current GDB debug thread is invalid!");
|
||||
send_gdb_packet("E03");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
__writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
State->u.WriteMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]);
|
||||
BufferLength = hex_to_address(strstr(&gdb_input[1], ",") + 1);
|
||||
if (BufferLength == 0)
|
||||
{
|
||||
/* Nothing to do */
|
||||
send_gdb_packet("OK");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
|
||||
State->u.WriteMemory.TransferCount = BufferLength;
|
||||
MessageData->Length = BufferLength;
|
||||
MessageData->Buffer = (CHAR*)OutBuffer;
|
||||
|
||||
OutPtr = OutBuffer;
|
||||
blob_ptr = strstr(strstr(&gdb_input[1], ",") + 1, ":") + 1;
|
||||
while (BufferLength)
|
||||
{
|
||||
if (BufferLength >= 4)
|
||||
{
|
||||
*((ULONG*)OutPtr) = *((ULONG*)blob_ptr);
|
||||
OutPtr += 4;
|
||||
blob_ptr += 4;
|
||||
BufferLength -= 4;
|
||||
}
|
||||
else if (BufferLength >= 2)
|
||||
{
|
||||
*((USHORT*)OutPtr) = *((USHORT*)blob_ptr);
|
||||
OutPtr += 2;
|
||||
blob_ptr += 2;
|
||||
BufferLength -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*OutPtr++ = *blob_ptr++;
|
||||
BufferLength--;
|
||||
}
|
||||
}
|
||||
|
||||
/* KD will reply with KdSendPacket. Catch it */
|
||||
KdpSendPacketHandler = WriteMemorySendHandler;
|
||||
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
WriteBreakPointSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData)
|
||||
{
|
||||
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
||||
|
||||
if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
||||
{
|
||||
// KdAssert
|
||||
KDDBGPRINT("Wrong packet type (%lu) received after DbgKdWriteBreakPointApi request.\n", PacketType);
|
||||
while (1);
|
||||
}
|
||||
|
||||
if (State->ApiNumber != DbgKdWriteBreakPointApi)
|
||||
{
|
||||
KDDBGPRINT("Wrong API number (%lu) after DbgKdWriteBreakPointApi request.\n", State->ApiNumber);
|
||||
}
|
||||
|
||||
/* Check status */
|
||||
if (!NT_SUCCESS(State->ReturnStatus))
|
||||
{
|
||||
KDDBGPRINT("Inserting breakpoint failed!\n");
|
||||
send_gdb_ntstatus(State->ReturnStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Keep track of the address+handle couple */
|
||||
ULONG i;
|
||||
for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
|
||||
{
|
||||
if (BreakPointHandles[i].Address == 0)
|
||||
{
|
||||
BreakPointHandles[i].Address = (ULONG_PTR)State->u.WriteBreakPoint.BreakPointAddress;
|
||||
BreakPointHandles[i].Handle = State->u.WriteBreakPoint.BreakPointHandle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
send_gdb_packet("OK");
|
||||
}
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
handle_gdb_insert_breakpoint(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
State->ReturnStatus = STATUS_SUCCESS; /* ? */
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
if (MessageData)
|
||||
MessageData->Length = 0;
|
||||
*MessageLength = 0;
|
||||
|
||||
switch (gdb_input[1])
|
||||
{
|
||||
case '0':
|
||||
{
|
||||
ULONG_PTR Address = hex_to_address(&gdb_input[3]);
|
||||
ULONG i;
|
||||
BOOLEAN HasFreeSlot = FALSE;
|
||||
|
||||
KDDBGPRINT("Inserting breakpoint at %p.\n", (void*)Address);
|
||||
|
||||
for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
|
||||
{
|
||||
if (BreakPointHandles[i].Address == 0)
|
||||
HasFreeSlot = TRUE;
|
||||
}
|
||||
|
||||
if (!HasFreeSlot)
|
||||
{
|
||||
/* We don't have a way to keep track of this break point. Fail. */
|
||||
KDDBGPRINT("No breakpoint slot available!\n");
|
||||
send_gdb_packet("E01");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
|
||||
State->ApiNumber = DbgKdWriteBreakPointApi;
|
||||
State->u.WriteBreakPoint.BreakPointAddress = Address;
|
||||
/* FIXME : ignoring all other Z0 arguments */
|
||||
|
||||
/* KD will reply with KdSendPacket. Catch it */
|
||||
KdpSendPacketHandler = WriteBreakPointSendHandler;
|
||||
return KdPacketReceived;
|
||||
}
|
||||
}
|
||||
|
||||
KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
|
||||
send_gdb_packet("E01");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
RestoreBreakPointSendHandler(
|
||||
_In_ ULONG PacketType,
|
||||
_In_ PSTRING MessageHeader,
|
||||
_In_ PSTRING MessageData)
|
||||
{
|
||||
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
|
||||
ULONG i;
|
||||
|
||||
if (PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|
||||
{
|
||||
// KdAssert
|
||||
KDDBGPRINT("Wrong packet type (%lu) received after DbgKdRestoreBreakPointApi request.\n", PacketType);
|
||||
while (1);
|
||||
}
|
||||
|
||||
if (State->ApiNumber != DbgKdRestoreBreakPointApi)
|
||||
{
|
||||
KDDBGPRINT("Wrong API number (%lu) after DbgKdRestoreBreakPointApi request.\n", State->ApiNumber);
|
||||
}
|
||||
|
||||
/* We ignore failure here. If DbgKdRestoreBreakPointApi fails,
|
||||
* this means that the breakpoint was already invalid for KD. So clean it up on our side. */
|
||||
for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
|
||||
{
|
||||
if (BreakPointHandles[i].Handle == State->u.RestoreBreakPoint.BreakPointHandle)
|
||||
{
|
||||
BreakPointHandles[i].Address = 0;
|
||||
BreakPointHandles[i].Handle = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
send_gdb_packet("OK");
|
||||
|
||||
KdpSendPacketHandler = NULL;
|
||||
KdpManipulateStateHandler = NULL;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
handle_gdb_remove_breakpoint(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
State->ReturnStatus = STATUS_SUCCESS; /* ? */
|
||||
State->Processor = CurrentStateChange.Processor;
|
||||
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
|
||||
if (MessageData)
|
||||
MessageData->Length = 0;
|
||||
*MessageLength = 0;
|
||||
|
||||
switch (gdb_input[1])
|
||||
{
|
||||
case '0':
|
||||
{
|
||||
ULONG_PTR Address = hex_to_address(&gdb_input[3]);
|
||||
ULONG i, Handle = 0;
|
||||
|
||||
KDDBGPRINT("Removing breakpoint on %p.\n", (void*)Address);
|
||||
|
||||
for (i = 0; i < (sizeof(BreakPointHandles) / sizeof(BreakPointHandles[0])); i++)
|
||||
{
|
||||
if (BreakPointHandles[i].Address == Address)
|
||||
{
|
||||
Handle = BreakPointHandles[i].Handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Handle == 0)
|
||||
{
|
||||
KDDBGPRINT("Received %s, but breakpoint was never inserted ?!\n", gdb_input);
|
||||
send_gdb_packet("E01");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
|
||||
State->ApiNumber = DbgKdRestoreBreakPointApi;
|
||||
State->u.RestoreBreakPoint.BreakPointHandle = Handle;
|
||||
/* FIXME : ignoring all other z0 arguments */
|
||||
|
||||
/* KD will reply with KdSendPacket. Catch it */
|
||||
KdpSendPacketHandler = RestoreBreakPointSendHandler;
|
||||
return KdPacketReceived;
|
||||
}
|
||||
}
|
||||
|
||||
KDDBGPRINT("Unhandled 'Z' packet: %s\n", gdb_input);
|
||||
send_gdb_packet("E01");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
handle_gdb_c(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
/* Tell GDB everything is fine, we will handle it */
|
||||
send_gdb_packet("OK");
|
||||
|
||||
if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
|
||||
{
|
||||
DBGKM_EXCEPTION64* Exception = &CurrentStateChange.u.Exception;
|
||||
ULONG_PTR ProgramCounter = KdpGetContextPc(&CurrentContext);
|
||||
|
||||
/* See if we should update the program counter */
|
||||
if (Exception && (Exception->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
|
||||
&& ProgramCounter == KdDebuggerDataBlock->BreakpointWithStatus.Pointer)
|
||||
{
|
||||
/* We must get past the breakpoint instruction */
|
||||
KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
|
||||
|
||||
SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
|
||||
KdpManipulateStateHandler = ContinueManipulateStateHandler;
|
||||
return KdPacketReceived;
|
||||
}
|
||||
}
|
||||
|
||||
return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
handle_gdb_s(
|
||||
_Out_ DBGKD_MANIPULATE_STATE64* State,
|
||||
_Out_ PSTRING MessageData,
|
||||
_Out_ PULONG MessageLength,
|
||||
_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
KDDBGPRINT("Single stepping.\n");
|
||||
/* Set CPU single step mode and continue */
|
||||
KdpSetSingleStep(&CurrentContext);
|
||||
SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
|
||||
KdpManipulateStateHandler = ContinueManipulateStateHandler;
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
static
|
||||
KDSTATUS
|
||||
handle_gdb_v(
|
||||
|
@ -464,36 +873,19 @@ handle_gdb_v(
|
|||
if (gdb_input[5] == '?')
|
||||
{
|
||||
/* Report what we support */
|
||||
send_gdb_packet("vCont;c;C;s;S");
|
||||
send_gdb_packet("vCont;c;s");
|
||||
return (KDSTATUS)-1;
|
||||
}
|
||||
|
||||
if (strncmp(gdb_input, "vCont;c", 7) == 0)
|
||||
{
|
||||
DBGKM_EXCEPTION64* Exception = NULL;
|
||||
return handle_gdb_c(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
|
||||
/* Tell GDB everything is fine, we will handle it */
|
||||
send_gdb_packet("OK");
|
||||
|
||||
if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
|
||||
Exception = &CurrentStateChange.u.Exception;
|
||||
|
||||
/* See if we should update the program counter (unlike windbg, gdb doesn't do it for us) */
|
||||
if (Exception && (Exception->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT)
|
||||
&& (Exception->ExceptionRecord.ExceptionInformation[0] == 0))
|
||||
{
|
||||
ULONG_PTR ProgramCounter;
|
||||
|
||||
/* So we must get past the breakpoint instruction */
|
||||
ProgramCounter = KdpGetContextPc(&CurrentContext);
|
||||
KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
|
||||
|
||||
SetContextManipulateHandler(State, MessageData, MessageLength, KdContext);
|
||||
KdpManipulateStateHandler = ContinueManipulateStateHandler;
|
||||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);
|
||||
if (strncmp(gdb_input, "vCont;s", 7) == 0)
|
||||
{
|
||||
|
||||
return handle_gdb_s(State, MessageData, MessageLength, KdContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,11 +916,14 @@ gdb_receive_and_interpret_packet(
|
|||
{
|
||||
case '?':
|
||||
/* Send the Status */
|
||||
gdb_send_exception(TRUE);
|
||||
gdb_send_exception();
|
||||
break;
|
||||
case '!':
|
||||
send_gdb_packet("OK");
|
||||
break;
|
||||
case 'c':
|
||||
Status = handle_gdb_c(State, MessageData, MessageLength, KdContext);
|
||||
break;
|
||||
case 'g':
|
||||
gdb_send_registers();
|
||||
break;
|
||||
|
@ -544,17 +939,28 @@ gdb_receive_and_interpret_packet(
|
|||
case 'q':
|
||||
handle_gdb_query();
|
||||
break;
|
||||
case 's':
|
||||
Status = handle_gdb_s(State, MessageData, MessageLength, KdContext);
|
||||
break;
|
||||
case 'T':
|
||||
handle_gdb_thread_alive();
|
||||
break;
|
||||
case 'v':
|
||||
Status = handle_gdb_v(State, MessageData, MessageLength, KdContext);
|
||||
break;
|
||||
case 'X':
|
||||
Status = handle_gdb_write_mem(State, MessageData, MessageLength, KdContext);
|
||||
break;
|
||||
case 'z':
|
||||
Status = handle_gdb_remove_breakpoint(State, MessageData, MessageLength, KdContext);
|
||||
break;
|
||||
case 'Z':
|
||||
Status = handle_gdb_insert_breakpoint(State, MessageData, MessageLength, KdContext);
|
||||
break;
|
||||
default:
|
||||
/* We don't know how to handle this request. Maybe this is something for KD */
|
||||
State->ReturnStatus = STATUS_NOT_SUPPORTED;
|
||||
/* We don't know how to handle this request. */
|
||||
KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input);
|
||||
return KdPacketReceived;
|
||||
send_gdb_packet("");
|
||||
}
|
||||
} while (Status == (KDSTATUS)-1);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ KDSTATUS
|
|||
NTAPI
|
||||
gdb_receive_packet(_Inout_ PKD_CONTEXT KdContext)
|
||||
{
|
||||
char* ByteBuffer = gdb_input;
|
||||
UCHAR* ByteBuffer = (UCHAR*)gdb_input;
|
||||
UCHAR Byte;
|
||||
KDSTATUS Status;
|
||||
CHAR CheckSum = 0, ReceivedCheckSum;
|
||||
|
@ -60,9 +60,18 @@ gdb_receive_packet(_Inout_ PKD_CONTEXT KdContext)
|
|||
*ByteBuffer = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
*ByteBuffer++ = Byte;
|
||||
CheckSum += (CHAR)Byte;
|
||||
|
||||
/* See if we should escape */
|
||||
if (Byte == 0x7d)
|
||||
{
|
||||
Status = KdpReceiveByte(&Byte);
|
||||
if (Status != KdPacketReceived)
|
||||
return Status;
|
||||
CheckSum += (CHAR)Byte;
|
||||
Byte ^= 0x20;
|
||||
}
|
||||
*ByteBuffer++ = Byte;
|
||||
}
|
||||
|
||||
/* Get Check sum (two bytes) */
|
||||
|
@ -80,6 +89,7 @@ end:
|
|||
if (ReceivedCheckSum != CheckSum)
|
||||
{
|
||||
/* Do not acknowledge to GDB */
|
||||
KDDBGPRINT("Check sums don't match!");
|
||||
KdpSendByte('-');
|
||||
return KdPacketNeedsResend;
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ gdb_send_debug_io(
|
|||
}
|
||||
|
||||
void
|
||||
gdb_send_exception(BOOLEAN WithThread)
|
||||
gdb_send_exception()
|
||||
{
|
||||
char gdb_out[1024];
|
||||
char* ptr = gdb_out;
|
||||
|
@ -184,20 +184,16 @@ gdb_send_exception(BOOLEAN WithThread)
|
|||
}
|
||||
else
|
||||
ptr += sprintf(ptr, "05");
|
||||
if (WithThread)
|
||||
{
|
||||
|
||||
#if MONOPROCESS
|
||||
ptr += sprintf(ptr, "thread:%" PRIxPTR ";",
|
||||
handle_to_gdb_tid(PsGetThreadId(Thread)));
|
||||
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)));
|
||||
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);
|
||||
/* Add program counter */
|
||||
gdb_append_pc_to_exception(Thread, ptr);
|
||||
send_gdb_packet(gdb_out);
|
||||
}
|
||||
|
||||
|
|
|
@ -251,28 +251,4 @@ gdb_send_register(void)
|
|||
}
|
||||
}
|
||||
|
||||
char*
|
||||
gdb_append_pc_to_exception(
|
||||
_In_ PETHREAD Thread,
|
||||
_Inout_ char* ptr)
|
||||
{
|
||||
/* Get EIP */
|
||||
unsigned short ptrSize;
|
||||
unsigned char* EipPtr = thread_to_reg(Thread, EIP, &ptrSize);
|
||||
|
||||
/* Print it */
|
||||
ptr += sprintf(ptr, "08:");
|
||||
*ptr++ = hex_chars[EipPtr[0] >> 4];
|
||||
*ptr++ = hex_chars[EipPtr[0] & 0xF];
|
||||
*ptr++ = hex_chars[EipPtr[1] >> 4];
|
||||
*ptr++ = hex_chars[EipPtr[1] & 0xF];
|
||||
*ptr++ = hex_chars[EipPtr[2] >> 4];
|
||||
*ptr++ = hex_chars[EipPtr[2] & 0xF];
|
||||
*ptr++ = hex_chars[EipPtr[3] >> 4];
|
||||
*ptr++ = hex_chars[EipPtr[3] & 0xF];
|
||||
*ptr++ = ';';
|
||||
*ptr++ = '\0';
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -303,7 +303,6 @@ KdpReceiveByte(_Out_ PUCHAR OutByte)
|
|||
return KdPacketReceived;
|
||||
}
|
||||
|
||||
KDDBGPRINT("CpGetByte returned %u.\n", CpStatus);
|
||||
return KdPacketTimedOut;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include <pstypes.h>
|
||||
|
||||
#define KDDEBUG /* uncomment to enable debugging this dll */
|
||||
//#define KDDEBUG /* uncomment to enable debugging this dll */
|
||||
|
||||
/* To undefine once https://sourceware.org/bugzilla/show_bug.cgi?id=17397 is resolved */
|
||||
#define MONOPROCESS 1
|
||||
|
@ -83,7 +83,7 @@ char hex_value(char ch);
|
|||
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, _In_ BOOLEAN WithPrefix);
|
||||
void gdb_send_exception(BOOLEAN WithThread);
|
||||
void gdb_send_exception(void);
|
||||
void send_gdb_ntstatus(_In_ NTSTATUS Status);
|
||||
extern const char hex_chars[];
|
||||
|
||||
|
@ -113,15 +113,18 @@ extern PETHREAD find_thread(_In_ UINT_PTR Pid, _In_ UINT_PTR Tid);
|
|||
/* arch_sup.c */
|
||||
extern void gdb_send_register(void);
|
||||
extern void gdb_send_registers(void);
|
||||
extern char* gdb_append_pc_to_exception(_In_ PETHREAD Thread, _Inout_ char* ptr);
|
||||
|
||||
/* Architecture specific defines. See ntoskrnl/include/internal/arch/ke.h */
|
||||
#ifdef _M_IX86
|
||||
/* Handling passing over the breakpoint instruction */
|
||||
# define KdpGetContextPc(Context) \
|
||||
((Context)->Eip)
|
||||
# define KdpSetContextPc(Context, ProgramCounter) \
|
||||
((Context)->Eip = (ProgramCounter))
|
||||
# define KD_BREAKPOINT_SIZE sizeof(UCHAR)
|
||||
/* Single step mode */
|
||||
# define KdpSetSingleStep(Context) \
|
||||
((Context)->EFlags |= EFLAGS_TF)
|
||||
#else
|
||||
# error "Please define relevant macros for your architecture"
|
||||
#endif
|
||||
|
|
|
@ -160,7 +160,7 @@ send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange)
|
|||
#else
|
||||
gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread));
|
||||
#endif
|
||||
gdb_send_exception(FALSE);
|
||||
gdb_send_exception();
|
||||
/* Next receive call will ask for the context */
|
||||
KdpManipulateStateHandler = GetContextManipulateHandler;
|
||||
break;
|
||||
|
@ -394,6 +394,13 @@ KdSendPacket(
|
|||
IN PSTRING MessageData,
|
||||
IN OUT PKD_CONTEXT KdContext)
|
||||
{
|
||||
/* Override if we have some debug print from KD. */
|
||||
if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
|
||||
{
|
||||
send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Maybe we are in a send <-> receive loop that GDB doesn't need to know about */
|
||||
if (KdpSendPacketHandler)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue