xref: /reactos/ntoskrnl/kdbg/kdbg.c (revision 5140a990)
1 /*
2  * PROJECT:     ReactOS KDBG Kernel Debugger
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Kernel Debugger Initialization
5  * COPYRIGHT:   Copyright 2020-2021 Hervé Poussineau <hpoussin@reactos.org>
6  *              Copyright 2021 Jérôme Gardou <jerome.gardou@reactos.org>
7  *              Copyright 2023 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
8  */
9 
10 /* INCLUDES ******************************************************************/
11 
12 #include <ntoskrnl.h>
13 #include "kdb.h"
14 
15 /* GLOBALS *******************************************************************/
16 
17 static ULONG KdbgNextApiNumber = DbgKdContinueApi;
18 static CONTEXT KdbgContext;
19 static EXCEPTION_RECORD64 KdbgExceptionRecord;
20 static BOOLEAN KdbgFirstChanceException;
21 static NTSTATUS KdbgContinueStatus = STATUS_SUCCESS;
22 
23 /* FUNCTIONS *****************************************************************/
24 
25 NTSTATUS
26 NTAPI
27 KdD0Transition(VOID)
28 #undef KdD0Transition
29 #define pKdD0Transition KdD0Transition
30 {
31     /* Call KdTerm */
32     return pKdD0Transition();
33 }
34 
35 NTSTATUS
36 NTAPI
37 KdD3Transition(VOID)
38 #undef KdD3Transition
39 #define pKdD3Transition KdD3Transition
40 {
41     /* Call KdTerm */
42     return pKdD3Transition();
43 }
44 
45 NTSTATUS
46 NTAPI
47 KdSave(
48     _In_ BOOLEAN SleepTransition)
49 #undef KdSave
50 #define pKdSave KdSave
51 {
52     /* Call KdTerm */
53     return pKdSave(SleepTransition);
54 }
55 
56 NTSTATUS
57 NTAPI
58 KdRestore(
59     _In_ BOOLEAN SleepTransition)
60 #undef KdRestore
61 #define pKdRestore KdRestore
62 {
63     /* Call KdTerm */
64     return pKdRestore(SleepTransition);
65 }
66 
67 VOID
68 NTAPI
69 KdSendPacket(
70     _In_ ULONG PacketType,
71     _In_ PSTRING MessageHeader,
72     _In_opt_ PSTRING MessageData,
73     _Inout_ PKD_CONTEXT Context)
74 #undef KdSendPacket
75 #define pKdSendPacket KdSendPacket
76 {
77     if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
78     {
79         /* Call KdTerm */
80         pKdSendPacket(PacketType, MessageHeader, MessageData, Context);
81         return;
82     }
83 
84     /* Debugger-only packets */
85     if (PacketType == PACKET_TYPE_KD_STATE_CHANGE64)
86     {
87         PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange = (PDBGKD_ANY_WAIT_STATE_CHANGE)MessageHeader->Buffer;
88         if (WaitStateChange->NewState == DbgKdLoadSymbolsStateChange)
89         {
90             /* Load or unload symbols */
91             PLDR_DATA_TABLE_ENTRY LdrEntry;
92             if (KdbpSymFindModule((PVOID)(ULONG_PTR)WaitStateChange->u.LoadSymbols.BaseOfDll, -1, &LdrEntry))
93             {
94                 KdbSymProcessSymbols(LdrEntry, !WaitStateChange->u.LoadSymbols.UnloadSymbols);
95             }
96             return;
97         }
98         else if (WaitStateChange->NewState == DbgKdExceptionStateChange)
99         {
100             KdbgNextApiNumber = DbgKdGetContextApi;
101             KdbgExceptionRecord = WaitStateChange->u.Exception.ExceptionRecord;
102             KdbgFirstChanceException = WaitStateChange->u.Exception.FirstChance;
103             return;
104         }
105     }
106     else if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
107     {
108         PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer;
109         if (ManipulateState->ApiNumber == DbgKdGetContextApi)
110         {
111             KD_CONTINUE_TYPE Result;
112 
113             /* Check if this is an assertion failure */
114             if (KdbgExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE)
115             {
116                 /* Bump EIP to the instruction following the int 2C */
117                 KeSetContextPc(&KdbgContext, KeGetContextPc(&KdbgContext) + 2);
118             }
119 
120             Result = KdbEnterDebuggerException(&KdbgExceptionRecord,
121                                                KdbgContext.SegCs & 1,
122                                                &KdbgContext,
123                                                KdbgFirstChanceException);
124 #if 0
125             /* Manually dump the stack for the user */
126             KeRosDumpStackFrames(NULL, 0);
127             Result = kdHandleException;
128 #endif
129             if (Result != kdHandleException)
130                 KdbgContinueStatus = STATUS_SUCCESS;
131             else
132                 KdbgContinueStatus = STATUS_UNSUCCESSFUL;
133             KdbgNextApiNumber = DbgKdSetContextApi;
134             return;
135         }
136         else if (ManipulateState->ApiNumber == DbgKdSetContextApi)
137         {
138             KdbgNextApiNumber = DbgKdContinueApi;
139             return;
140         }
141     }
142 
143     KdbPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
144     return;
145 }
146 
147 KDSTATUS
148 NTAPI
149 KdReceivePacket(
150     _In_ ULONG PacketType,
151     _Out_ PSTRING MessageHeader,
152     _Out_ PSTRING MessageData,
153     _Out_ PULONG DataLength,
154     _Inout_ PKD_CONTEXT Context)
155 #undef KdReceivePacket
156 #define pKdReceivePacket KdReceivePacket
157 {
158     if (PacketType == PACKET_TYPE_KD_POLL_BREAKIN)
159     {
160         // FIXME TODO: Implement break-in for the debugger
161         // and return KdPacketReceived when handled properly.
162         return KdPacketTimedOut;
163     }
164 
165     if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
166     {
167         /* Call KdTerm */
168         return pKdReceivePacket(PacketType,
169                                 MessageHeader,
170                                 MessageData,
171                                 DataLength,
172                                 Context);
173     }
174 
175     /* Debugger-only packets */
176     if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
177     {
178         PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer;
179         RtlZeroMemory(MessageHeader->Buffer, MessageHeader->MaximumLength);
180         if (KdbgNextApiNumber == DbgKdGetContextApi)
181         {
182             ManipulateState->ApiNumber = DbgKdGetContextApi;
183             MessageData->Length = 0;
184             MessageData->Buffer = (PCHAR)&KdbgContext;
185             return KdPacketReceived;
186         }
187         else if (KdbgNextApiNumber == DbgKdSetContextApi)
188         {
189             ManipulateState->ApiNumber = DbgKdSetContextApi;
190             MessageData->Length = sizeof(KdbgContext);
191             MessageData->Buffer = (PCHAR)&KdbgContext;
192             return KdPacketReceived;
193         }
194         else if (KdbgNextApiNumber != DbgKdContinueApi)
195         {
196             KdbPrintf("%s:%d is UNIMPLEMENTED\n", __FUNCTION__, __LINE__);
197         }
198         ManipulateState->ApiNumber = DbgKdContinueApi;
199         ManipulateState->u.Continue.ContinueStatus = KdbgContinueStatus;
200 
201         /* Prepare for next time */
202         KdbgNextApiNumber = DbgKdContinueApi;
203         KdbgContinueStatus = STATUS_SUCCESS;
204 
205         return KdPacketReceived;
206     }
207 
208     KdbPrintf("%s: PacketType %d is UNIMPLEMENTED\n", __FUNCTION__, PacketType);
209     return KdPacketTimedOut;
210 }
211 
212 /* EOF */
213