- Add a callback mechanism permitting to "simulate" KD send <-> receive loop without having to actually communicate to GDB
 - Use that to update the program counter when cont'ing a breakpoint
Now cont'ing an assertion failure is possible, since we actually get beyond the int 3 instruction

svn path=/trunk/; revision=64127
This commit is contained in:
Jérôme Gardou 2014-09-12 20:23:08 +00:00
parent 476ad09335
commit 1bbea7c093
3 changed files with 198 additions and 12 deletions

View file

@ -11,6 +11,7 @@
static HANDLE gdb_run_thread;
static HANDLE gdb_dbg_process;
HANDLE gdb_dbg_thread;
CONTEXT CurrentContext;
/* PRIVATE FUNCTIONS **********************************************************/
static
@ -199,6 +200,147 @@ handle_gdb_read_mem(
return KdPacketReceived;
}
static
VOID
GetCurrentContextSendHandler(
_In_ ULONG PacketType,
_In_ PSTRING MessageHeader,
_In_ PSTRING MessageData
)
{
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
const CONTEXT* Context = (const CONTEXT*)MessageData->Buffer;
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|| (State->ApiNumber != DbgKdGetContextApi)
|| (MessageData->Length < sizeof(*Context)))
{
/* Should we bugcheck ? */
while (1);
}
/* Just copy it */
RtlCopyMemory(&CurrentContext, Context, sizeof(*Context));
}
static
VOID
GetCurrentContext(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext,
_In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
)
{
State->ApiNumber = DbgKdGetContextApi;
State->Processor = CurrentStateChange.Processor;
State->ReturnStatus = STATUS_SUCCESS;
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
MessageData->Length = 0;
/* Update the send <-> receive loop handler */
KdpSendPacketHandler = GetCurrentContextSendHandler;
KdpManipulateStateHandler = ManipulateStateHandler;
}
static
VOID
SetContextSendHandler(
_In_ ULONG PacketType,
_In_ PSTRING MessageHeader,
_In_ PSTRING MessageData
)
{
DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
/* We just confirm that all went well */
if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE)
|| (State->ApiNumber != DbgKdSetContextApi)
|| (State->ReturnStatus != STATUS_SUCCESS))
{
/* Should we bugcheck ? */
while (1);
}
}
static
KDSTATUS
SetContext(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext,
_In_opt_ KDP_MANIPULATESTATE_HANDLER ManipulateStateHandler
)
{
State->ApiNumber = DbgKdSetContextApi;
State->Processor = CurrentStateChange.Processor;
State->ReturnStatus = STATUS_SUCCESS;
State->ProcessorLevel = CurrentStateChange.ProcessorLevel;
MessageData->Length = sizeof(CurrentContext);
if (MessageData->MaximumLength < sizeof(CurrentContext))
{
while (1);
}
RtlCopyMemory(MessageData->Buffer, &CurrentContext, sizeof(CurrentContext));
/* Update the send <-> receive loop handlers */
KdpSendPacketHandler = SetContextSendHandler;
KdpManipulateStateHandler = ManipulateStateHandler;
return KdPacketReceived;
}
static
KDSTATUS
SendContinue(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext
)
{
/* 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;
/* We definitely are at the end of the send <-> receive loop, if any */
KdpSendPacketHandler = NULL;
KdpManipulateStateHandler = NULL;
/* Tell GDB we are fine */
send_gdb_packet("OK");
return KdPacketReceived;
}
static
KDSTATUS
UpdateProgramCounterSendContinue(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext)
{
ULONG_PTR ProgramCounter;
/* So we must get past the breakpoint instruction */
ProgramCounter = KdpGetContextPc(&CurrentContext);
KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
/* Set the context and continue */
SetContext(State, MessageData, MessageLength, KdContext, SendContinue);
return KdPacketReceived;
}
static
KDSTATUS
handle_gdb_v(
@ -222,18 +364,21 @@ handle_gdb_v(
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;
DBGKM_EXCEPTION64* Exception = NULL;
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))
{
/* So we get the context, update it and send it back */
GetCurrentContext(State, MessageData, MessageLength, KdContext, UpdateProgramCounterSendContinue);
return KdPacketReceived;
}
return SendContinue(State, MessageData, MessageLength, KdContext);
}
}

View file

@ -25,6 +25,19 @@ extern ULONG KdpDbgPrint(const char* Format, ...);
#define KDDBGPRINT KdpDbgPrint
#endif
/* Callbacks to simulate a KdReceive <-> KdSend loop without GDB being aware of it */
typedef VOID (*KDP_SEND_HANDLER)(
_In_ ULONG PacketType,
_In_ PSTRING MessageHeader,
_In_ PSTRING MessageData
);
typedef KDSTATUS (*KDP_MANIPULATESTATE_HANDLER)(
_Out_ DBGKD_MANIPULATE_STATE64* State,
_Out_ PSTRING MessageData,
_Out_ PULONG MessageLength,
_Inout_ PKD_CONTEXT KdContext
);
/* 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);
@ -49,8 +62,22 @@ KDSTATUS NTAPI KdpReceiveByte(_Out_ PUCHAR OutByte);
extern DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
extern DBGKD_GET_VERSION64 KdVersion;
extern KDDEBUGGER_DATA64* KdDebuggerDataBlock;
extern KDP_SEND_HANDLER KdpSendPacketHandler;
extern KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler;
/* arch_sup.c */
void gdb_send_registers(void);
/* Architecture specific defines. See ntoskrnl/include/internal/arch/ke.h */
#ifdef _M_IX86
# define KdpGetContextPc(Context) \
((Context)->Eip)
# define KdpSetContextPc(Context, ProgramCounter) \
((Context)->Eip = (ProgramCounter))
# define KD_BREAKPOINT_SIZE sizeof(UCHAR)
#else
# error "Please define relevant macros for your architecture"
#endif
#endif /* _KDGDB_H_ */

View file

@ -12,6 +12,9 @@
DBGKD_ANY_WAIT_STATE_CHANGE CurrentStateChange;
DBGKD_GET_VERSION64 KdVersion;
KDDEBUGGER_DATA64* KdDebuggerDataBlock;
/* Callbacks used to communicate with KD aside from GDB */
KDP_SEND_HANDLER KdpSendPacketHandler = NULL;
KDP_MANIPULATESTATE_HANDLER KdpManipulateStateHandler = NULL;
/* LOCALS *********************************************************************/
static BOOLEAN FakeNextManipulatePacket = FALSE;
@ -159,6 +162,10 @@ KdReceivePacket(
State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer;
/* Maybe we are in a send<->receive loop that GDB doesn't need to know about */
if (KdpManipulateStateHandler != NULL)
return KdpManipulateStateHandler(State, MessageData, DataLength, KdContext);
if (FakeNextManipulatePacket)
{
FakeNextManipulatePacket = FALSE;
@ -183,6 +190,13 @@ KdSendPacket(
IN PSTRING MessageData,
IN OUT PKD_CONTEXT KdContext)
{
/* Maybe we are in a send <-> receive loop that GDB doesn't need to know about */
if (KdpSendPacketHandler)
{
KdpSendPacketHandler(PacketType, MessageHeader, MessageData);
return;
}
switch (PacketType)
{
case PACKET_TYPE_KD_STATE_CHANGE64: