static void handle_gdb_thread_alive(void) { ULONG_PTR Pid, Tid; PETHREAD Thread; #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) send_gdb_packet("OK"); else send_gdb_packet("E03"); }
void gdb_send_registers(void) { CHAR Registers[16*8 + 1]; UCHAR* RegisterPtr; unsigned i; unsigned short size; CHAR* ptr = Registers; KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid); KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)); if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) || gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)) { for(i=0; i < 16; i++) { RegisterPtr = ctx_to_reg(&CurrentContext, i, &size); *ptr++ = hex_chars[RegisterPtr[0] >> 4]; *ptr++ = hex_chars[RegisterPtr[0] & 0xF]; *ptr++ = hex_chars[RegisterPtr[1] >> 4]; *ptr++ = hex_chars[RegisterPtr[1] & 0xF]; *ptr++ = hex_chars[RegisterPtr[2] >> 4]; *ptr++ = hex_chars[RegisterPtr[2] & 0xF]; *ptr++ = hex_chars[RegisterPtr[3] >> 4]; *ptr++ = hex_chars[RegisterPtr[3] & 0xF]; } } else {
KDSTATUS gdb_receive_and_interpret_packet( _Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext) { KDSTATUS Status; do { Status = gdb_receive_packet(KdContext); KDDBGPRINT("KDGBD: Packet received with status %u\n", Status); if (Status != KdPacketReceived) return Status; Status = (KDSTATUS)-1; switch (gdb_input[0]) { case '?': /* Send the Status */ gdb_send_exception(TRUE); break; case '!': send_gdb_packet("OK"); break; case 'g': gdb_send_registers(); break; case 'H': handle_gdb_set_thread(); break; case 'm': Status = handle_gdb_read_mem(State, MessageData, MessageLength, KdContext); break; case 'p': gdb_send_register(); break; case 'q': handle_gdb_query(); break; case 'T': handle_gdb_thread_alive(); break; case 'v': Status = handle_gdb_v(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; KDDBGPRINT("Unsupported GDB command: %s.\n", gdb_input); return KdPacketReceived; } } while (Status == (KDSTATUS)-1); return Status; }
/* H* packets */ static void handle_gdb_set_thread(void) { 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]); 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 send_gdb_packet("OK"); break; default: KDDBGPRINT("KDGBD: Unknown 'H' command: %s\n", gdb_input); send_gdb_packet(""); } }
KDSTATUS SetContextManipulateHandler( _Out_ DBGKD_MANIPULATE_STATE64* State, _Out_ PSTRING MessageData, _Out_ PULONG MessageLength, _Inout_ PKD_CONTEXT KdContext ) { State->ApiNumber = DbgKdSetContextApi; State->Processor = CurrentStateChange.Processor; State->ReturnStatus = STATUS_SUCCESS; State->ProcessorLevel = CurrentStateChange.ProcessorLevel; MessageData->Length = sizeof(CurrentContext); if (MessageData->MaximumLength < sizeof(CurrentContext)) { KDDBGPRINT("Wrong message length %u.\n", MessageData->MaximumLength); while (1); } RtlCopyMemory(MessageData->Buffer, &CurrentContext, sizeof(CurrentContext)); /* Update the send <-> receive loop handlers */ KdpSendPacketHandler = SetContextSendHandler; KdpManipulateStateHandler = NULL; return KdPacketReceived; }
static VOID GetVersionSendHandler( _In_ ULONG PacketType, _In_ PSTRING MessageHeader, _In_ PSTRING MessageData) { DBGKD_MANIPULATE_STATE64* State = (DBGKD_MANIPULATE_STATE64*)MessageHeader->Buffer; LIST_ENTRY* DebuggerDataList; /* Confirm that all went well */ if ((PacketType != PACKET_TYPE_KD_STATE_MANIPULATE) || (State->ApiNumber != DbgKdGetVersionApi) || !NT_SUCCESS(State->ReturnStatus)) { /* FIXME: should detach from KD and go along without debugging */ KDDBGPRINT("Wrong packet received after asking for data.\n"); while(1); } /* Copy the relevant data */ RtlCopyMemory(&KdVersion, &State->u.GetVersion64, sizeof(KdVersion)); DebuggerDataList = (LIST_ENTRY*)(ULONG_PTR)KdVersion.DebuggerDataList; KdDebuggerDataBlock = CONTAINING_RECORD(DebuggerDataList->Flink, KDDEBUGGER_DATA64, Header.List); ProcessListHead = (LIST_ENTRY*)KdDebuggerDataBlock->PsActiveProcessHead.Pointer; /* Now we can get the context for the current state */ KdpSendPacketHandler = NULL; KdpManipulateStateHandler = GetContextManipulateHandler; }
VOID NTAPI KdSendPacket( IN ULONG PacketType, IN PSTRING MessageHeader, 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: 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: KDDBGPRINT("Unknown packet type %u.\n", PacketType); while (1); } }
static VOID FirstSendHandler( _In_ ULONG PacketType, _In_ PSTRING MessageHeader, _In_ PSTRING MessageData) { DBGKD_ANY_WAIT_STATE_CHANGE* StateChange = (DBGKD_ANY_WAIT_STATE_CHANGE*)MessageHeader->Buffer; PETHREAD Thread; if (PacketType == PACKET_TYPE_KD_DEBUG_IO) { /* This is not the packet we are waiting for */ send_kd_debug_io((DBGKD_DEBUG_IO*)MessageHeader->Buffer, MessageData); return; } if (PacketType != PACKET_TYPE_KD_STATE_CHANGE64) { KDDBGPRINT("First KD packet is not a state change!\n"); /* FIXME: What should we send back to KD ? */ while(1); } KDDBGPRINT("KDGDB: START!\n"); Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread; /* Set up the current state */ CurrentStateChange = *StateChange; gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread)); #if MONOPROCESS gdb_dbg_pid = 0; #else gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread)); #endif /* This is the idle process. Save it! */ TheIdleThread = Thread; TheIdleProcess = (PEPROCESS)Thread->Tcb.ApcState.Process; KDDBGPRINT("Pid Tid of the first message: %" PRIxPTR", %" PRIxPTR ".\n", gdb_dbg_pid, gdb_dbg_tid); /* The next receive call will be asking for the version data */ KdpSendPacketHandler = NULL; KdpManipulateStateHandler = GetVersionManipulateStateHandler; }
static void send_kd_state_change(DBGKD_ANY_WAIT_STATE_CHANGE* StateChange) { InException = TRUE; switch (StateChange->NewState) { case DbgKdLoadSymbolsStateChange: { /* We don't care about symbols loading */ KdpManipulateStateHandler = ContinueManipulateStateHandler; break; } case DbgKdExceptionStateChange: { PETHREAD Thread = (PETHREAD)(ULONG_PTR)StateChange->Thread; /* Save current state for later GDB queries */ CurrentStateChange = *StateChange; KDDBGPRINT("Exception 0x%08x in thread p%p.%p.\n", StateChange->u.Exception.ExceptionRecord.ExceptionCode, PsGetThreadProcessId(Thread), PsGetThreadId(Thread)); /* Set the current debugged process/thread accordingly */ gdb_dbg_tid = handle_to_gdb_tid(PsGetThreadId(Thread)); #if MONOPROCESS gdb_dbg_pid = 0; #else gdb_dbg_pid = handle_to_gdb_pid(PsGetThreadProcessId(Thread)); #endif gdb_send_exception(FALSE); /* Next receive call will ask for the context */ KdpManipulateStateHandler = GetContextManipulateHandler; break; } default: KDDBGPRINT("Unknown StateChange %u.\n", StateChange->NewState); while (1); } }
static void ReadMemorySendHandler( _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); while (1); } if (State->ApiNumber != DbgKdReadVirtualMemoryApi) { KDDBGPRINT("Wrong API number (%lu) after DbgKdReadVirtualMemoryApi request.\n", State->ApiNumber); } /* Check status */ if (!NT_SUCCESS(State->ReturnStatus)) send_gdb_ntstatus(State->ReturnStatus); else send_gdb_memory(MessageData->Buffer, MessageData->Length); KdpSendPacketHandler = NULL; KdpManipulateStateHandler = NULL; #if !MONOPROCESS /* Reset the TLB */ if ((gdb_dbg_pid != 0) && gdb_pid_to_handle(gdb_dbg_pid) != PsGetCurrentProcessId()) { __writecr3(PsGetCurrentProcess()->Pcb.DirectoryTableBase[0]); } #endif }
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] == '?') { /* Report what we support */ send_gdb_packet("vCont;c;C;s;S"); return (KDSTATUS)-1; } if (strncmp(gdb_input, "vCont;c", 7) == 0) { DBGKM_EXCEPTION64* Exception = NULL; /* 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); } } KDDBGPRINT("Unhandled 'v' packet: %s\n", gdb_input); return KdPacketReceived; }
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 default: KDDBGPRINT("Unknown ApiNumber %u.\n", State->ApiNumber); while (1); } }
static void send_kd_debug_io( _In_ DBGKD_DEBUG_IO* DebugIO, _In_ PSTRING String) { if (InException) return; switch (DebugIO->ApiNumber) { case DbgKdPrintStringApi: gdb_send_debug_io(String, TRUE); break; default: KDDBGPRINT("Unknown ApiNumber %u.\n", DebugIO->ApiNumber); while (1); } }
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 ? */ KDDBGPRINT("BAD BAD BAD not manipulating state for sending context.\n"); while (1); } KdpSendPacketHandler = NULL; }
NTSTATUS NTAPI KdpPortInitialize(IN ULONG ComPortNumber, IN ULONG ComPortBaudRate) { NTSTATUS Status; KDDBGPRINT("KdpPortInitialize, Port = COM%ld\n", ComPortNumber); Status = CpInitialize(&KdDebugComPort, UlongToPtr(BaseArray[ComPortNumber]), ComPortBaudRate); if (!NT_SUCCESS(Status)) { return STATUS_INVALID_PARAMETER; } else { KdComPortInUse = KdDebugComPort.Address; return STATUS_SUCCESS; } }
static KDSTATUS handle_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; #if !MONOPROCESS /* Set the TLB according to the process being read. Pid 0 means any process. */ 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 gdb_receive_and_interpret_packet(State, MessageData, MessageLength, KdContext); } __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; }
static VOID GetContextSendHandler( _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 ? */ KDDBGPRINT("ERROR: Received wrong packet from KD.\n"); while (1); } /* Just copy it */ RtlCopyMemory(&CurrentContext, Context, sizeof(*Context)); KdpSendPacketHandler = NULL; }
static void* thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size) { /* See if the guy got a stack */ if (Thread->Tcb.InitialStack == NULL) { static const void* NullValue = NULL; /* Terminated thread ? */ switch (reg_name) { case ESP: case EBP: case EIP: KDDBGPRINT("Returning NULL for register %d.\n", reg_name); *size = 4; return &NullValue; default: return NULL; } } else if (Thread->Tcb.TrapFrame) { PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame; *size = 4; switch (reg_name) { case EAX: return &TrapFrame->Eax; case ECX: return &TrapFrame->Ecx; case EDX: return &TrapFrame->Edx; case EBX: return &TrapFrame->Ebx; case ESP: return (TrapFrame->PreviousPreviousMode == KernelMode) ? &TrapFrame->TempEsp : &TrapFrame->HardwareEsp; case EBP: return &TrapFrame->Ebp; case ESI: return &TrapFrame->Esi; case EDI: return &TrapFrame->Edi; case EIP: return &TrapFrame->Eip; case EFLAGS: return &TrapFrame->EFlags; case CS: return &TrapFrame->SegCs; case SS: return &TrapFrame->HardwareSegSs; case DS: return &TrapFrame->SegDs; case ES: return &TrapFrame->SegEs; case FS: return &TrapFrame->SegFs; case GS: return &TrapFrame->SegGs; default: KDDBGPRINT("Unhandled regname: %d.\n", reg_name); } } else { /* The thread was not yet scheduled */ *size = 4; switch(reg_name) { case ESP: return &Thread->Tcb.KernelStack; case EBP: return &((ULONG*)Thread->Tcb.KernelStack)[4]; case EIP: return &Thread->StartAddress; default: return NULL; } } return NULL; }
KDSTATUS NTAPI gdb_receive_packet(_Inout_ PKD_CONTEXT KdContext) { UCHAR* ByteBuffer = (UCHAR*)gdb_input; UCHAR Byte; KDSTATUS Status; CHAR CheckSum = 0, ReceivedCheckSum; do { Status = KdpReceiveByte(&Byte); if (Status != KdPacketReceived) return Status; if (Byte == 0x03) { KDDBGPRINT("BREAK!"); 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; } 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) */ 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 */ KDDBGPRINT("Check sums don't match!"); KdpSendByte('-'); return KdPacketNeedsResend; } /* Acknowledge */ KdpSendByte('+'); return KdPacketReceived; }
/* q* packets */ static void handle_gdb_query(void) { if (strncmp(gdb_input, "qSupported:", 11) == 0) { #if MONOPROCESS send_gdb_packet("PacketSize=1000;"); #else send_gdb_packet("PacketSize=1000;multiprocess+;"); #endif return; } if (strncmp(gdb_input, "qAttached", 9) == 0) { #if MONOPROCESS 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) send_gdb_packet("0"); else send_gdb_packet("1"); #endif return; } if (strncmp(gdb_input, "qRcmd,", 6) == 0) { send_gdb_packet("OK"); return; } 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 send_gdb_packet(gdb_out); return; } if ((strncmp(gdb_input, "qfThreadInfo", 12) == 0) || (strncmp(gdb_input, "qsThreadInfo", 12) == 0)) { BOOLEAN FirstThread = TRUE; PEPROCESS Process; PETHREAD Thread; char gdb_out[1024]; char* ptr = gdb_out; BOOLEAN Resuming = strncmp(gdb_input, "qsThreadInfo", 12) == 0; /* Keep track of where we are. */ static LIST_ENTRY* CurrentProcessEntry; static LIST_ENTRY* CurrentThreadEntry; ptr = gdb_out; *ptr++ = 'm'; /* NULL terminate in case we got nothing more to iterate */ *ptr = '\0'; if (!Resuming) { /* 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; } if (CurrentProcessEntry == NULL) /* Ps is not initialized */ { send_gdb_packet(Resuming ? "l" : gdb_out); return; } /* List all the processes */ for ( ; CurrentProcessEntry != ProcessListHead; CurrentProcessEntry = CurrentProcessEntry->Flink) { Process = CONTAINING_RECORD(CurrentProcessEntry, EPROCESS, ActiveProcessLinks); if (CurrentThreadEntry != NULL) CurrentThreadEntry = CurrentThreadEntry->Flink; else CurrentThreadEntry = Process->ThreadListHead.Flink; /* List threads from this process */ for ( ; CurrentThreadEntry != &Process->ThreadListHead; CurrentThreadEntry = CurrentThreadEntry->Flink) { Thread = CONTAINING_RECORD(CurrentThreadEntry, ETHREAD, ThreadListEntry); /* See if we should add a comma */ if (FirstThread) { FirstThread = FALSE; } else { *ptr++ = ','; } #if MONOPROCESS ptr += _snprintf(ptr, 1024 - (ptr - gdb_out), "%p", handle_to_gdb_tid(Thread->Cid.UniqueThread)); #else ptr += _snprintf(ptr, 1024 - (ptr - gdb_out), "p%p.%p", handle_to_gdb_pid(Process->UniqueProcessId), handle_to_gdb_tid(Thread->Cid.UniqueThread)); #endif if (ptr > (gdb_out + 1024)) { /* send what we got */ send_gdb_packet(gdb_out); /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */ return; } } /* We're done for this process */ CurrentThreadEntry = NULL; } if (gdb_out[1] == '\0') { /* We didn't iterate over anything, meaning we were already done */ send_gdb_packet("l"); } else { send_gdb_packet(gdb_out); } /* GDB can ask anything at this point, it isn't necessarily a qsThreadInfo packet */ return; } 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[2]); Tid = hex_to_tid(strstr(gdb_input, ".") + 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); } gdb_send_debug_io(&String, FALSE); return; } if (strncmp(gdb_input, "qOffsets", 8) == 0) { /* We load ntoskrnl at 0x80800000 while compiling it at 0x00800000 base adress */ send_gdb_packet("TextSeg=80000000"); return; } if (strcmp(gdb_input, "qTStatus") == 0) { /* No tracepoint support */ send_gdb_packet("T0"); return; } KDDBGPRINT("KDGDB: Unknown query: %s\n", gdb_input); send_gdb_packet(""); return; }
/****************************************************************************** * \name KdpReceivePacketLeader * \brief Recieves a packet leadr from the KD port. * \param PacketLeader Pointer to an ULONG that receives the packet leader. * \return KDP_PACKET_RECEIVED if successful. * KDP_PACKET_TIMEOUT if the receive timed out. * KDP_PACKET_RESEND if a breakin byte was detected. */ KDP_STATUS NTAPI KdpReceivePacketLeader( OUT PULONG PacketLeader) { UCHAR Index = 0, Byte, Buffer[4]; KDP_STATUS KdStatus; /* Set first character to 0 */ Buffer[0] = 0; do { /* Receive a single byte */ KdStatus = KdpReceiveByte(&Byte); /* Check for timeout */ if (KdStatus == KDP_PACKET_TIMEOUT) { /* Check if we already got a breakin byte */ if (Buffer[0] == BREAKIN_PACKET_BYTE) { return KDP_PACKET_RESEND; } /* Report timeout */ return KDP_PACKET_TIMEOUT; } /* Check if we received a byte */ if (KdStatus == KDP_PACKET_RECEIVED) { /* Check if this is a valid packet leader byte */ if (Byte == PACKET_LEADER_BYTE || Byte == CONTROL_PACKET_LEADER_BYTE) { /* Check if we match the first byte */ if (Byte != Buffer[0]) { /* No, this is the new byte 0! */ Index = 0; } /* Store the byte in the buffer */ Buffer[Index] = Byte; /* Continue with next byte */ Index++; continue; } /* Check for breakin byte */ if (Byte == BREAKIN_PACKET_BYTE) { KDDBGPRINT("BREAKIN_PACKET_BYTE\n"); Index = 0; Buffer[0] = Byte; continue; } } /* Restart */ Index = 0; Buffer[0] = 0; } while (Index < 4); /* Enable the debugger */ KdDebuggerNotPresent = FALSE; SharedUserData->KdDebuggerEnabled |= 0x00000002; /* Return the received packet leader */ *PacketLeader = *(PULONG)Buffer; return KDP_PACKET_RECEIVED; }
/****************************************************************************** * \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) { /* HACK */ KdpDbgPrint = LoaderBlock->u.I386.CommonDataArea; KDDBGPRINT("KdDebuggerInitialize0\n"); /* 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); }