1 /*
2 * PROJECT: ReactOS KD dll - GDB stub
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Base functions for the kernel debugger
5 * COPYRIGHT: Copyright 2021 Jérôme Gardou
6 */
7
8 #include "kdgdb.h"
9
10 enum reg_name
11 {
12 RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP,
13 R8, R9, R10, R11, R12, R13, R14, R15,
14 RIP,
15 EFLAGS,
16 CS, SS, DS, ES, FS, GS,
17 ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7,
18 FCTRL, FSTAT, FTAG, FISEG, FIOFF, FOSEG, FOOFF, FOP
19 };
20
21 static const unsigned char reg_size[] =
22 {
23 8, 8, 8, 8, 8, 8, 8, 8,
24 8, 8, 8, 8, 8, 8, 8, 8,
25 8,
26 4,
27 4, 4, 4, 4, 4, 4,
28 10, 10, 10, 10, 10, 10, 10, 10,
29 8, 8, 8, 8, 8, 8, 8, 8
30 };
31
32 static
33 void*
ctx_to_reg(CONTEXT * ctx,enum reg_name name)34 ctx_to_reg(CONTEXT* ctx, enum reg_name name)
35 {
36 switch (name)
37 {
38 case RAX: return &ctx->Rax;
39 case RBX: return &ctx->Rbx;
40 case RCX: return &ctx->Rcx;
41 case RDX: return &ctx->Rdx;
42 case RSP: return &ctx->Rsp;
43 case RBP: return &ctx->Rbp;
44 case RSI: return &ctx->Rsi;
45 case RDI: return &ctx->Rdi;
46 case RIP: return &ctx->Rip;
47 case R8: return &ctx->R8;
48 case R9: return &ctx->R9;
49 case R10: return &ctx->R10;
50 case R11: return &ctx->R11;
51 case R12: return &ctx->R12;
52 case R13: return &ctx->R13;
53 case R14: return &ctx->R14;
54 case R15: return &ctx->R15;
55 case EFLAGS: return &ctx->EFlags;
56 case CS: return &ctx->SegCs;
57 case DS: return &ctx->SegSs;
58 case ES: return &ctx->SegEs;
59 case FS: return &ctx->SegFs;
60 case GS: return &ctx->SegGs;
61 case SS: return &ctx->SegSs;
62 }
63 #undef return_reg
64 return 0;
65 }
66
67 static
68 void*
thread_to_reg(PETHREAD Thread,enum reg_name reg_name)69 thread_to_reg(PETHREAD Thread, enum reg_name reg_name)
70 {
71 static const void* NullValue = NULL;
72
73 #if 0
74 if (Thread->Tcb.TrapFrame)
75 {
76 PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame;
77
78 switch (reg_name)
79 {
80 case RAX: return &TrapFrame->Rax;
81 case RBX: return &TrapFrame->Rbx;
82 case RCX: return &TrapFrame->Rcx;
83 case RDX: return &TrapFrame->Rdx;
84 case RSP: return &TrapFrame->Rsp;
85 case RBP: return &TrapFrame->Rbp;
86 case RSI: return &TrapFrame->Rsi;
87 case RDI: return &TrapFrame->Rdi;
88 case RIP: return &TrapFrame->Rip;
89 case R8: return &TrapFrame->R8;
90 case R9: return &TrapFrame->R9;
91 case R10: return &TrapFrame->R10;
92 case R11: return &TrapFrame->R11;
93 case EFLAGS: return &TrapFrame->EFlags;
94 case CS: return &TrapFrame->SegCs;
95 case DS: return &TrapFrame->SegSs;
96 case ES: return &TrapFrame->SegEs;
97 case FS: return &TrapFrame->SegFs;
98 case GS: return &TrapFrame->SegGs;
99 case SS: return &TrapFrame->SegSs;
100 default:
101 KDDBGPRINT("Unhandled regname: %d.\n", reg_name);
102 }
103 }
104 else
105 #endif
106 if (!Thread->Tcb.InitialStack)
107 {
108 /* Terminated thread ? */
109 switch (reg_name)
110 {
111 case RSP:
112 case RBP:
113 case RIP:
114 KDDBGPRINT("Returning NULL for register %d.\n", reg_name);
115 return &NullValue;
116 default:
117 return NULL;
118 }
119 }
120 else
121 {
122 switch(reg_name)
123 {
124 case RSP: return &Thread->Tcb.KernelStack;
125 case RIP:
126 {
127 PULONG_PTR Rsp = Thread->Tcb.KernelStack;
128 return &Rsp[3];
129 }
130 case RBP:
131 {
132 PULONG_PTR Rsp = Thread->Tcb.KernelStack;
133 return &Rsp[4];
134 }
135 default:
136 return NULL;
137 }
138 }
139
140 return NULL;
141 }
142
143 KDSTATUS
gdb_send_registers(void)144 gdb_send_registers(void)
145 {
146 CHAR RegisterStr[17];
147 UCHAR* RegisterPtr;
148 unsigned short i;
149 unsigned short size;
150
151 start_gdb_packet();
152
153 KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
154 KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
155 if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
156 gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
157 {
158 for (i = 0; i < 24; i++)
159 {
160 RegisterPtr = ctx_to_reg(&CurrentContext, i);
161 size = reg_size[i] * 2;
162 RegisterStr[size] = 0;
163 while (size)
164 {
165 size--;
166 RegisterStr[size] = hex_chars[RegisterPtr[size/2] & 0xF];
167 size--;
168 RegisterStr[size] = hex_chars[RegisterPtr[size/2] >> 4];
169 }
170
171 send_gdb_partial_packet(RegisterStr);
172 }
173 }
174 else
175 {
176 PETHREAD DbgThread;
177
178 DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
179
180 if (DbgThread == NULL)
181 {
182 /* Thread is dead */
183 send_gdb_partial_packet("E03");
184 return finish_gdb_packet();
185 }
186
187 for (i = 0; i < 24; i++)
188 {
189 RegisterPtr = thread_to_reg(DbgThread, i);
190 size = reg_size[i] * 2;
191 RegisterStr[size] = 0;
192
193 while (size)
194 {
195 if (RegisterPtr)
196 {
197 size--;
198 RegisterStr[size] = hex_chars[RegisterPtr[size/2] & 0xF];
199 size--;
200 RegisterStr[size] = hex_chars[RegisterPtr[size/2] >> 4];
201 }
202 else
203 {
204 size--;
205 RegisterStr[size] = 'x';
206 size--;
207 RegisterStr[size] = 'x';
208 }
209 }
210
211 send_gdb_partial_packet(RegisterStr);
212 }
213 }
214
215 return finish_gdb_packet();
216 }
217
218 KDSTATUS
gdb_send_register(void)219 gdb_send_register(void)
220 {
221 enum reg_name reg_name;
222 void *ptr;
223
224 /* Get the GDB register name (gdb_input = "pXX") */
225 reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]);
226
227 if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
228 gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
229 {
230 /* We can get it from the context of the current exception */
231 ptr = ctx_to_reg(&CurrentContext, reg_name);
232 }
233 else
234 {
235 PETHREAD DbgThread;
236
237 DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
238
239 if (DbgThread == NULL)
240 {
241 /* Thread is dead */
242 return send_gdb_packet("E03");
243 }
244
245 ptr = thread_to_reg(DbgThread, reg_name);
246 }
247
248 if (!ptr)
249 {
250 unsigned char size = reg_size[reg_name];
251 start_gdb_packet();
252 while (size--)
253 send_gdb_partial_packet("xx");
254 return finish_gdb_packet();
255 }
256 else
257 {
258 KDDBGPRINT("KDDBG : Sending registers as memory.\n");
259 return send_gdb_memory(ptr, reg_size[reg_name]);
260 }
261 }
262
263
264