1 /*
2 * COPYRIGHT: GPL, see COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/base/kddll/gdb_input.c
5 * PURPOSE: Base functions for the kernel debugger.
6 */
7
8 #include "kdgdb.h"
9
10 enum reg_name
11 {
12 EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
13 EIP,
14 EFLAGS,
15 CS, SS, DS, ES, FS, GS,
16 ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7,
17 FCTRL, FSTAT, FTAG, FISEG, FIOFF, FOSEG, FOOFF, FOP,
18 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
19 MXCSR
20 };
21
22 static
23 void*
ctx_to_reg(CONTEXT * ctx,enum reg_name name,unsigned short * size)24 ctx_to_reg(CONTEXT* ctx, enum reg_name name, unsigned short* size)
25 {
26 /* For general registers: 32bits */
27 *size = 4;
28 switch (name)
29 {
30 case EAX: return &ctx->Eax;
31 case EBX: return &ctx->Ebx;
32 case ECX: return &ctx->Ecx;
33 case EDX: return &ctx->Edx;
34 case ESP: return &ctx->Esp;
35 case EBP: return &ctx->Ebp;
36 case ESI: return &ctx->Esi;
37 case EDI: return &ctx->Edi;
38 case EIP: return &ctx->Eip;
39 case EFLAGS: return &ctx->EFlags;
40 case CS: return &ctx->SegCs;
41 case DS: return &ctx->SegDs;
42 case ES: return &ctx->SegEs;
43 case FS: return &ctx->SegFs;
44 case GS: return &ctx->SegGs;
45 case SS: return &ctx->SegSs;
46 /* 80 bits */
47 case ST0:
48 case ST1:
49 case ST2:
50 case ST3:
51 case ST4:
52 case ST5:
53 case ST6:
54 case ST7:
55 *size = 10;
56 return &ctx->FloatSave.RegisterArea[10 * (name - ST0)];
57 /* X87 registers */
58 case FCTRL: return &ctx->FloatSave.ControlWord;
59 case FSTAT: return &ctx->FloatSave.StatusWord;
60 case FTAG: return &ctx->FloatSave.TagWord;
61 case FISEG: return &ctx->FloatSave.DataSelector;
62 case FIOFF: return &ctx->FloatSave.DataOffset;
63 case FOSEG: return &ctx->FloatSave.ErrorSelector;
64 case FOOFF: return &ctx->FloatSave.ErrorOffset;
65 case FOP: return &ctx->FloatSave.Cr0NpxState;
66 /* SSE */
67 case XMM0:
68 case XMM1:
69 case XMM2:
70 case XMM3:
71 case XMM4:
72 case XMM5:
73 case XMM6:
74 case XMM7:
75 *size = 16;
76 return &ctx->ExtendedRegisters[160 + (name - XMM0)*16];
77 case MXCSR: return &ctx->ExtendedRegisters[24];
78 }
79 return 0;
80 }
81
82 static
83 void*
thread_to_reg(PETHREAD Thread,enum reg_name reg_name,unsigned short * size)84 thread_to_reg(PETHREAD Thread, enum reg_name reg_name, unsigned short* size)
85 {
86 static const void* NullValue = NULL;
87
88 if (!Thread->Tcb.InitialStack)
89 {
90 /* Terminated thread ? */
91 switch (reg_name)
92 {
93 case ESP:
94 case EBP:
95 case EIP:
96 KDDBGPRINT("Returning NULL for register %d.\n", reg_name);
97 *size = 4;
98 return &NullValue;
99 default:
100 return NULL;
101 }
102 }
103 #if 0
104 else if (Thread->Tcb.TrapFrame)
105 {
106 PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame;
107
108 *size = 4;
109 switch (reg_name)
110 {
111 case EAX: return &TrapFrame->Eax;
112 case ECX: return &TrapFrame->Ecx;
113 case EDX: return &TrapFrame->Edx;
114 case EBX: return &TrapFrame->Ebx;
115 case ESP: return (TrapFrame->PreviousPreviousMode == KernelMode) ?
116 &TrapFrame->TempEsp : &TrapFrame->HardwareEsp;
117 case EBP: return &TrapFrame->Ebp;
118 case ESI: return &TrapFrame->Esi;
119 case EDI: return &TrapFrame->Edi;
120 case EIP: return &TrapFrame->Eip;
121 case EFLAGS: return &TrapFrame->EFlags;
122 case CS: return &TrapFrame->SegCs;
123 case SS: return &TrapFrame->HardwareSegSs;
124 case DS: return &TrapFrame->SegDs;
125 case ES: return &TrapFrame->SegEs;
126 case FS: return &TrapFrame->SegFs;
127 case GS: return &TrapFrame->SegGs;
128 default:
129 KDDBGPRINT("Unhandled regname: %d.\n", reg_name);
130 }
131 }
132 #endif
133 else
134 {
135 static PULONG Esp;
136 Esp = Thread->Tcb.KernelStack;
137 *size = 4;
138 switch(reg_name)
139 {
140 case EBP: return &Esp[3];
141 case ESP: return &Esp;
142 case EIP: return &NullValue;
143 default:
144 return NULL;
145 }
146 }
147
148 return NULL;
149 }
150
151 KDSTATUS
gdb_send_registers(void)152 gdb_send_registers(void)
153 {
154 CHAR RegisterStr[9];
155 UCHAR* RegisterPtr;
156 unsigned i;
157 unsigned short size;
158
159 RegisterStr[8] = '\0';
160
161 start_gdb_packet();
162
163 KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
164 KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
165 if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
166 gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
167 {
168 for(i=0; i < 16; i++)
169 {
170 RegisterPtr = ctx_to_reg(&CurrentContext, i, &size);
171 RegisterStr[0] = hex_chars[RegisterPtr[0] >> 4];
172 RegisterStr[1] = hex_chars[RegisterPtr[0] & 0xF];
173 RegisterStr[2] = hex_chars[RegisterPtr[1] >> 4];
174 RegisterStr[3] = hex_chars[RegisterPtr[1] & 0xF];
175 RegisterStr[4] = hex_chars[RegisterPtr[2] >> 4];
176 RegisterStr[5] = hex_chars[RegisterPtr[2] & 0xF];
177 RegisterStr[6] = hex_chars[RegisterPtr[3] >> 4];
178 RegisterStr[7] = hex_chars[RegisterPtr[3] & 0xF];
179
180 send_gdb_partial_packet(RegisterStr);
181 }
182 }
183 else
184 {
185 PETHREAD DbgThread;
186
187 DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
188
189 if (DbgThread == NULL)
190 {
191 /* Thread is dead */
192 send_gdb_partial_packet("E03");
193 return finish_gdb_packet();
194 }
195
196 for(i=0; i < 16; i++)
197 {
198 RegisterPtr = thread_to_reg(DbgThread, i, &size);
199 if (RegisterPtr)
200 {
201 RegisterStr[0] = hex_chars[RegisterPtr[0] >> 4];
202 RegisterStr[1] = hex_chars[RegisterPtr[0] & 0xF];
203 RegisterStr[2] = hex_chars[RegisterPtr[1] >> 4];
204 RegisterStr[3] = hex_chars[RegisterPtr[1] & 0xF];
205 RegisterStr[4] = hex_chars[RegisterPtr[2] >> 4];
206 RegisterStr[5] = hex_chars[RegisterPtr[2] & 0xF];
207 RegisterStr[6] = hex_chars[RegisterPtr[3] >> 4];
208 RegisterStr[7] = hex_chars[RegisterPtr[3] & 0xF];
209
210 send_gdb_partial_packet(RegisterStr);
211 }
212 else
213 {
214 send_gdb_partial_packet("xxxxxxxx");
215 }
216 }
217 }
218
219 return finish_gdb_packet();
220 }
221
222 KDSTATUS
gdb_send_register(void)223 gdb_send_register(void)
224 {
225 enum reg_name reg_name;
226 void *ptr;
227 unsigned short size;
228
229 /* Get the GDB register name (gdb_input = "pXX") */
230 reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]);
231
232 if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
233 gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
234 {
235 /* We can get it from the context of the current exception */
236 ptr = ctx_to_reg(&CurrentContext, reg_name, &size);
237 }
238 else
239 {
240 PETHREAD DbgThread;
241
242 DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
243
244 if (DbgThread == NULL)
245 {
246 /* Thread is dead */
247 return send_gdb_packet("E03");
248 }
249
250 ptr = thread_to_reg(DbgThread, reg_name, &size);
251 }
252
253 if (!ptr)
254 {
255 /* Undefined. Let's assume 32 bit register */
256 return send_gdb_packet("xxxxxxxx");
257 }
258 else
259 {
260 KDDBGPRINT("KDDBG : Sending registers as memory.\n");
261 return send_gdb_memory(ptr, size);
262 }
263 }
264
265
266