Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069/* * 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 ULONG_PTR gdb_run_tid;static struct{ ULONG_PTR Address; ULONG Handle;} BreakPointHandles[32];
/* GLOBALS ********************************************************************/UINT_PTR gdb_dbg_pid;UINT_PTR gdb_dbg_tid;
static inlineKDSTATUSLOOP_IF_SUCCESS(int x){ return (x == KdPacketReceived) ? (KDSTATUS)-1 : x;}
/* PRIVATE FUNCTIONS **********************************************************/staticUINT_PTRhex_to_tid(char* buffer){ ULONG_PTR ret = 0; char hex; while (*buffer) { hex = hex_value(*buffer++); if (hex < 0) return ret; ret <<= 4; ret += hex; } return ret;}#define hex_to_pid hex_to_tid
staticULONG64hex_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 */staticKDSTATUShandle_gdb_set_thread(void){ KDSTATUS Status;
switch (gdb_input[1]) { case 'c': if (strcmp(&gdb_input[2], "-1") == 0) gdb_run_tid = (ULONG_PTR)-1; else gdb_run_tid = hex_to_tid(&gdb_input[2]); Status = send_gdb_packet("OK"); break; case 'g': KDDBGPRINT("Setting debug thread: %s.\n", gdb_input);#if MONOPROCESS gdb_dbg_pid = 0; if (strncmp(&gdb_input[2], "-1", 2) == 0) { gdb_dbg_tid = (UINT_PTR)-1; } else { gdb_dbg_tid = hex_to_tid(&gdb_input[2]); }#else if (strncmp(&gdb_input[2], "p-1", 3) == 0) { gdb_dbg_pid = (UINT_PTR)-1; gdb_dbg_tid = (UINT_PTR)-1; } else { char* ptr = strstr(gdb_input, ".") + 1; gdb_dbg_pid = hex_to_pid(&gdb_input[3]); if (strncmp(ptr, "-1", 2) == 0) gdb_dbg_tid = (UINT_PTR)-1; else gdb_dbg_tid = hex_to_tid(ptr); }#endif Status = send_gdb_packet("OK"); break; default: KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input); Status = send_gdb_packet(""); }
return Status;}
staticKDSTATUShandle_gdb_thread_alive(void){ ULONG_PTR Pid, Tid; PETHREAD Thread; KDSTATUS Status;
#if MONOPROCESS Pid = 0; Tid = hex_to_tid(&gdb_input[1]);
KDDBGPRINT("Checking if %p is alive.\n", Tid);
#else Pid = hex_to_pid(&gdb_input[2]); Tid = hex_to_tid(strstr(gdb_input, ".") + 1);
/* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL. * So loop. */ KDDBGPRINT("Checking if p%p.%p is alive.\n", Pid, Tid);#endif
Thread = find_thread(Pid, Tid);
if (Thread != NULL) Status = send_gdb_packet("OK"); else Status = send_gdb_packet("E03");
return Status;}
/* q* packets */staticKDSTATUShandle_gdb_query(void){ if (strncmp(gdb_input, "qSupported:", 11) == 0) {#if MONOPROCESS return send_gdb_packet("PacketSize=1000;qXfer:libraries:read+;");#else return send_gdb_packet("PacketSize=1000;multiprocess+;qXfer:libraries:read+;");#endif }
if (strncmp(gdb_input, "qAttached", 9) == 0) {#if MONOPROCESS return send_gdb_packet("1");#else UINT_PTR queried_pid = hex_to_pid(&gdb_input[10]); /* Let's say we created system process */ if (gdb_pid_to_handle(queried_pid) == NULL) return send_gdb_packet("0"); else return send_gdb_packet("1");#endif }
if (strncmp(gdb_input, "qRcmd,", 6) == 0) { return send_gdb_packet("OK"); }
if (strcmp(gdb_input, "qC") == 0) { char gdb_out[64];#if MONOPROCESS sprintf(gdb_out, "QC:%"PRIxPTR";", handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));#else sprintf(gdb_out, "QC:p%"PRIxPTR".%"PRIxPTR";", handle_to_gdb_pid(PsGetThreadProcessId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)), handle_to_gdb_tid(PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)));#endif return send_gdb_packet(gdb_out); }
if (strncmp(gdb_input, "qfThreadInfo", 12) == 0) { PEPROCESS Process; char gdb_out[40]; LIST_ENTRY* CurrentProcessEntry;
CurrentProcessEntry = ProcessListHead->Flink; if (CurrentProcessEntry == NULL) /* Ps is not initialized */ {#if MONOPROCESS return send_gdb_packet("m1");#else return send_gdb_packet("mp1.1");#endif }
/* We will push threads as we find them */ start_gdb_packet();
/* Start with the system thread */#if MONOPROCESS send_gdb_partial_packet("m1");#else send_gdb_partial_packet("mp1.1");#endif
/* List all the processes */ for ( ; CurrentProcessEntry != ProcessListHead; CurrentProcessEntry = CurrentProcessEntry->Flink) { LIST_ENTRY* CurrentThreadEntry;
Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks);
/* List threads from this process */ for ( CurrentThreadEntry = Process->ThreadListHead.Flink; CurrentThreadEntry != &Process->ThreadListHead; CurrentThreadEntry = CurrentThreadEntry->Flink) { PETHREAD Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry);
#if MONOPROCESS _snprintf(gdb_out, 40, ",%p", handle_to_gdb_tid(Thread->Cid.UniqueThread));#else _snprintf(gdb_out, 40, ",p%p.%p", handle_to_gdb_pid(Process->UniqueProcessId), handle_to_gdb_tid(Thread->Cid.UniqueThread));#endif send_gdb_partial_packet(gdb_out); } }
return finish_gdb_packet(); }
if (strncmp(gdb_input, "qsThreadInfo", 12) == 0) { /* We sent the whole thread list on first qfThreadInfo call */ return send_gdb_packet("l"); }
if (strncmp(gdb_input, "qGetTIBAddr:", 12) == 0) { ULONG_PTR Pid, Tid; PETHREAD Thread;
#if MONOPROCESS Pid = 0; Tid = hex_to_tid(&gdb_input[12]);
KDDBGPRINT(" %p.\n", Tid);
Thread = find_thread(Pid, Tid);#else Pid = hex_to_pid(&gdb_input[13]); Tid = hex_to_tid(strstr(&gdb_input[13], ".") + 1);
/* We cannot use PsLookupProcessThreadByCid as we could be running at any IRQL. * So loop. */ KDDBGPRINT(" p%p.%p.\n", Pid, Tid); Thread = find_thread(Pid, Tid);#endif return send_gdb_memory(&Thread->Tcb.Teb, sizeof(Thread->Tcb.Teb)); }
if (strncmp(gdb_input, "qThreadExtraInfo,", 17) == 0) { ULONG_PTR Pid, Tid; PETHREAD Thread; PEPROCESS Process; char out_string[64]; STRING String = {0, 64, out_string};
KDDBGPRINT("Giving extra info for");
#if MONOPROCESS Pid = 0; Tid = hex_to_tid(&gdb_input[17]);
KDDBGPRINT(" %p.\n", Tid);
Thread = find_thread(Pid, Tid); Process = CONTAINING_RECORD(Thread->Tcb.Process, EPROCESS, Pcb);#else 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. */ KDDBGPRINT(" p%p.%p.\n", Pid, Tid);
Process = find_process(Pid); Thread = find_thread(Pid, Tid);#endif
if (PsGetThreadProcessId(Thread) == 0) { String.Length = sprintf(out_string, "SYSTEM"); } else { String.Length = sprintf(out_string, "%.*s", 16, Process->ImageFileName); }
return gdb_send_debug_io(&String, FALSE); }
if (strcmp(gdb_input, "qTStatus") == 0) { /* No tracepoint support */ return send_gdb_packet("T0"); }
if (strcmp(gdb_input, "qSymbol::") == 0) { /* No need */ return send_gdb_packet("OK"); }
if (strncmp(gdb_input, "qXfer:libraries:read::", 22) == 0) { static LIST_ENTRY* CurrentEntry = NULL; char str_helper[256]; char name_helper[64]; ULONG_PTR Offset = hex_to_address(&gdb_input[22]); ULONG_PTR ToSend = hex_to_address(strstr(&gdb_input[22], ",") + 1); ULONG Sent = 0; static BOOLEAN allDone = FALSE;
KDDBGPRINT("KDGDB: qXfer:libraries:read !\n");
/* Start the packet */ start_gdb_packet();
if (allDone) { send_gdb_partial_packet("l"); allDone = FALSE; return finish_gdb_packet(); }
send_gdb_partial_packet("m"); Sent++;
/* Are we starting ? */ if (Offset == 0) { Sent += send_gdb_partial_binary("<?xml version=\"1.0\"?>", 21); Sent += send_gdb_partial_binary("<library-list>", 14);
CurrentEntry = ModuleListHead->Flink;
if (!CurrentEntry) { /* Ps is not initialized. Send end of XML data or mark that we are finished. */ Sent += send_gdb_partial_binary("</library-list>", 15); allDone = TRUE; return finish_gdb_packet(); } }
for ( ; CurrentEntry != ModuleListHead; CurrentEntry = CurrentEntry->Flink) { PLDR_DATA_TABLE_ENTRY TableEntry = CONTAINING_RECORD(CurrentEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); PVOID DllBase = (PVOID)((ULONG_PTR)TableEntry->DllBase + 0x1000); LONG mem_length; USHORT i;
/* Convert names to lower case. Yes this _is_ ugly */ for (i = 0; i < (TableEntry->BaseDllName.Length / sizeof(WCHAR)); i++) { name_helper[i] = (char)TableEntry->BaseDllName.Buffer[i]; if (name_helper[i] >= 'A' && name_helper[i] <= 'Z') name_helper[i] += 'a' - 'A'; } name_helper[i] = 0;
/* GDB doesn't load the file if you don't prefix it with a drive letter... */ mem_length = _snprintf(str_helper, 256, "<library name=\"C:\\%s\"><segment address=\"0x%p\"/></library>", &name_helper, DllBase);
/* DLL name must be too long. */ if (mem_length < 0) { KDDBGPRINT("Failed to report %wZ\n", &TableEntry->BaseDllName); continue; }
if ((Sent + mem_length) > ToSend) { /* We're done for this pass */ return finish_gdb_packet(); }
Sent += send_gdb_partial_binary(str_helper, mem_length); }
if ((ToSend - Sent) > 15) { Sent += send_gdb_partial_binary("</library-list>", 15); allDone = TRUE; }
return finish_gdb_packet(); }
KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input); return send_gdb_packet("");}
#if 0staticKDSTATUShandle_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
staticBOOLEANReadMemorySendHandler( _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 DbgKdReadVirtualMemoryApi request.\n", PacketType); return FALSE; }
if (State->ApiNumber != DbgKdReadVirtualMemoryApi) { KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State->ApiNumber); return FALSE; }
/* 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 (gdb_dbg_tid != 0) /* Reset the TLB */#else if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId())#endif { /* Only do this if Ps is initialized */ if (ProcessListHead->Flink) __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]); }
return TRUE;}
staticKDSTATUShandle_gdb_read_mem( _Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext){ State->ApiNumber = DbgKdReadVirtualMemoryApi; State->ReturnStatus = STATUS_SUCCESS; /* ? */ State->Processor = CurrentStateChange.Processor; State->ProcessorLevel = CurrentStateChange.ProcessorLevel; if (MessageData) MessageData->Length = 0; *MessageLength = 0;
/* 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!"); return LOOP_IF_SUCCESS(send_gdb_packet("E03")); }
AttachedProcess = AttachedThread->Tcb.Process; if (AttachedProcess == NULL) { KDDBGPRINT("The current GDB debug thread is invalid!"); return LOOP_IF_SUCCESS(send_gdb_packet("E03")); } __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!"); return LOOP_IF_SUCCESS(send_gdb_packet("E03")); } /* Only do this if Ps is initialized */ if (ProcessListHead->Flink) __writecr3(AttachedProcess->Pcb.DirectoryTableBase[0]); }#endif
State->u.ReadMemory.TargetBaseAddress = hex_to_address(&gdb_input[1]); State->u.ReadMemory.TransferCount = hex_to_address(strstr(&gdb_input[1], ",") + 1);
/* KD will reply with KdSendPacket. Catch it */ KdpSendPacketHandler = ReadMemorySendHandler; return KdPacketReceived;}
staticBOOLEANWriteMemorySendHandler( _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); return FALSE; }
if (State->ApiNumber != DbgKdWriteVirtualMemoryApi) { KDDBGPRINT("Wrong API number (%lu) after DbgKdWriteVirtualMemoryApi request.\n", State->ApiNumber); return FALSE; }
/* 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 { /* Only do this if Ps is initialized */ if (ProcessListHead->Flink) __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]); } return TRUE;}
staticKDSTATUShandle_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!"); return LOOP_IF_SUCCESS(send_gdb_packet("E03")); }
AttachedProcess = AttachedThread->Tcb.Process; if (AttachedProcess == NULL) { KDDBGPRINT("The current GDB debug thread is invalid!"); return LOOP_IF_SUCCESS(send_gdb_packet("E03")); } __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!"); return LOOP_IF_SUCCESS(send_gdb_packet("E03")); } /* Only do this if Ps is initialized */ if (ProcessListHead->Flink) __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 */ return LOOP_IF_SUCCESS(send_gdb_packet("OK")); }
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;}
staticBOOLEANWriteBreakPointSendHandler( _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); return FALSE; }
if (State->ApiNumber != DbgKdWriteBreakPointApi) { KDDBGPRINT("Wrong API number (%lu) after DbgKdWriteBreakPointApi request.\n", State->ApiNumber); return FALSE; }
/* 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; return TRUE;}
staticKDSTATUShandle_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"); return LOOP_IF_SUCCESS(send_gdb_packet("E01")); }
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); return LOOP_IF_SUCCESS(send_gdb_packet("E01"));}
staticBOOLEANRestoreBreakPointSendHandler( _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); return FALSE; }
if (State->ApiNumber != DbgKdRestoreBreakPointApi) { KDDBGPRINT("Wrong API number (%lu) after DbgKdRestoreBreakPointApi request.\n", State->ApiNumber); return FALSE; }
/* 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; return TRUE;}
staticKDSTATUShandle_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); return LOOP_IF_SUCCESS(send_gdb_packet("E01")); }
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); return LOOP_IF_SUCCESS(send_gdb_packet("E01"));}
staticKDSTATUShandle_gdb_c( _Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext){ KDSTATUS Status;
/* Tell GDB everything is fine, we will handle it */ Status = send_gdb_packet("OK"); if (Status != KdPacketReceived) return Status;
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->ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT) && ((*(KD_BREAKPOINT_TYPE*)ProgramCounter) == KD_BREAKPOINT_VALUE)) { /* We must get past the breakpoint instruction */ KdpSetContextPc(&CurrentContext, ProgramCounter + KD_BREAKPOINT_SIZE);
SetContextManipulateHandler(State, MessageData, MessageLength, KdContext); KdpManipulateStateHandler = ContinueManipulateStateHandler; return KdPacketReceived; }#if defined(_M_IX86) || defined(_M_AMD64) if ((Exception->ExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE) && ((*(KD_BREAKPOINT_TYPE*)ProgramCounter) == 0xCD) && (*((KD_BREAKPOINT_TYPE*)ProgramCounter + 1) == 0x2C)) { /* INT 2C (a.k.a. runtime check failure) */ KdpSetContextPc(&CurrentContext, ProgramCounter + 2);
SetContextManipulateHandler(State, MessageData, MessageLength, KdContext); KdpManipulateStateHandler = ContinueManipulateStateHandler; return KdPacketReceived; }#endif }
return ContinueManipulateStateHandler(State, MessageData, MessageLength, KdContext);}
staticKDSTATUShandle_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;}
staticKDSTATUShandle_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] == '?') { /* Report what we support */ return LOOP_IF_SUCCESS(send_gdb_packet("vCont;c;s")); }
if (strncmp(gdb_input, "vCont;c", 7) == 0) { return handle_gdb_c(State, MessageData, MessageLength, KdContext); }
if (strncmp(gdb_input, "vCont;s", 7) == 0) {
return handle_gdb_s(State, MessageData, MessageLength, KdContext); } }
KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input); return LOOP_IF_SUCCESS(send_gdb_packet(""));}
KDSTATUSgdb_receive_and_interpret_packet( _Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext){ KDSTATUS Status;
do { KDDBGPRINT("KDGBD: Receiving packet.\n"); Status = gdb_receive_packet(KdContext); KDDBGPRINT("KDGBD: Packet \"%s\" received with status %u\n", gdb_input, Status);
if (Status != KdPacketReceived) return Status;
Status = (KDSTATUS)-1;
switch (gdb_input[0]) { case '?': /* Send the Status */ Status = LOOP_IF_SUCCESS(gdb_send_exception()); break; case '!': Status = LOOP_IF_SUCCESS(send_gdb_packet("OK")); break; case 'c': case 'C': Status = handle_gdb_c(State, MessageData, MessageLength, KdContext); break; case 'g': Status = LOOP_IF_SUCCESS(gdb_send_registers()); break; case 'H': Status = LOOP_IF_SUCCESS(handle_gdb_set_thread()); break; case 'm': Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext); break; case 'p': Status = LOOP_IF_SUCCESS(gdb_send_register()); break; case 'q': Status = LOOP_IF_SUCCESS(handle_gdb_query()); break; case 's': Status = handle_gdb_s(State, MessageData, MessageLength, KdContext); break; case 'T': Status = LOOP_IF_SUCCESS(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. */ KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input); Status = LOOP_IF_SUCCESS(send_gdb_packet("")); } } while (Status == (KDSTATUS)-1);
return Status;}