xref: /reactos/drivers/base/kdgdb/i386_sup.c (revision 8a978a17)
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*
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*
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     else if (Thread->Tcb.TrapFrame)
104     {
105         PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame;
106 
107         *size = 4;
108         switch (reg_name)
109         {
110             case EAX: return &TrapFrame->Eax;
111             case ECX: return &TrapFrame->Ecx;
112             case EDX: return &TrapFrame->Edx;
113             case EBX: return &TrapFrame->Ebx;
114             case ESP: return (TrapFrame->PreviousPreviousMode == KernelMode) ?
115                     &TrapFrame->TempEsp : &TrapFrame->HardwareEsp;
116             case EBP: return &TrapFrame->Ebp;
117             case ESI: return &TrapFrame->Esi;
118             case EDI: return &TrapFrame->Edi;
119             case EIP: return &TrapFrame->Eip;
120             case EFLAGS: return &TrapFrame->EFlags;
121             case CS: return &TrapFrame->SegCs;
122             case SS: return &TrapFrame->HardwareSegSs;
123             case DS: return &TrapFrame->SegDs;
124             case ES: return &TrapFrame->SegEs;
125             case FS: return &TrapFrame->SegFs;
126             case GS: return &TrapFrame->SegGs;
127             default:
128                 KDDBGPRINT("Unhandled regname: %d.\n", reg_name);
129         }
130     }
131     else
132     {
133         static PULONG Esp;
134         Esp = Thread->Tcb.KernelStack;
135         *size = 4;
136         switch(reg_name)
137         {
138             case EBP: return &Esp[3];
139             case ESP: return &Esp;
140             case EIP: return &NullValue;
141             default:
142                 return NULL;
143         }
144     }
145 
146     return NULL;
147 }
148 
149 KDSTATUS
150 gdb_send_registers(void)
151 {
152     CHAR RegisterStr[9];
153     UCHAR* RegisterPtr;
154     unsigned i;
155     unsigned short size;
156 
157     RegisterStr[8] = '\0';
158 
159     start_gdb_packet();
160 
161     KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid);
162     KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread));
163     if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
164             gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
165     {
166         for(i=0; i < 16; i++)
167         {
168             RegisterPtr = ctx_to_reg(&CurrentContext, i, &size);
169             RegisterStr[0] = hex_chars[RegisterPtr[0] >> 4];
170             RegisterStr[1] = hex_chars[RegisterPtr[0] & 0xF];
171             RegisterStr[2] = hex_chars[RegisterPtr[1] >> 4];
172             RegisterStr[3] = hex_chars[RegisterPtr[1] & 0xF];
173             RegisterStr[4] = hex_chars[RegisterPtr[2] >> 4];
174             RegisterStr[5] = hex_chars[RegisterPtr[2] & 0xF];
175             RegisterStr[6] = hex_chars[RegisterPtr[3] >> 4];
176             RegisterStr[7] = hex_chars[RegisterPtr[3] & 0xF];
177 
178             send_gdb_partial_packet(RegisterStr);
179         }
180     }
181     else
182     {
183         PETHREAD DbgThread;
184 
185         DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
186 
187         if (DbgThread == NULL)
188         {
189             /* Thread is dead */
190             send_gdb_partial_packet("E03");
191             return finish_gdb_packet();
192         }
193 
194         for(i=0; i < 16; i++)
195         {
196             RegisterPtr = thread_to_reg(DbgThread, i, &size);
197             if (RegisterPtr)
198             {
199                 RegisterStr[0] = hex_chars[RegisterPtr[0] >> 4];
200                 RegisterStr[1] = hex_chars[RegisterPtr[0] & 0xF];
201                 RegisterStr[2] = hex_chars[RegisterPtr[1] >> 4];
202                 RegisterStr[3] = hex_chars[RegisterPtr[1] & 0xF];
203                 RegisterStr[4] = hex_chars[RegisterPtr[2] >> 4];
204                 RegisterStr[5] = hex_chars[RegisterPtr[2] & 0xF];
205                 RegisterStr[6] = hex_chars[RegisterPtr[3] >> 4];
206                 RegisterStr[7] = hex_chars[RegisterPtr[3] & 0xF];
207 
208                 send_gdb_partial_packet(RegisterStr);
209             }
210             else
211             {
212                 send_gdb_partial_packet("xxxxxxxx");
213             }
214         }
215     }
216 
217     return finish_gdb_packet();
218 }
219 
220 KDSTATUS
221 gdb_send_register(void)
222 {
223     enum reg_name reg_name;
224     void *ptr;
225     unsigned short size;
226 
227     /* Get the GDB register name (gdb_input = "pXX") */
228     reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]);
229 
230     if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) ||
231             gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread))
232     {
233         /* We can get it from the context of the current exception */
234         ptr = ctx_to_reg(&CurrentContext, reg_name, &size);
235     }
236     else
237     {
238         PETHREAD DbgThread;
239 
240         DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid);
241 
242         if (DbgThread == NULL)
243         {
244             /* Thread is dead */
245             return send_gdb_packet("E03");
246         }
247 
248         ptr = thread_to_reg(DbgThread, reg_name, &size);
249     }
250 
251     if (!ptr)
252     {
253         /* Undefined. Let's assume 32 bit register */
254         return send_gdb_packet("xxxxxxxx");
255     }
256     else
257     {
258         KDDBGPRINT("KDDBG : Sending registers as memory.\n");
259         return send_gdb_memory(ptr, size);
260     }
261 }
262 
263 
264