xref: /reactos/drivers/base/kdgdb/i386_sup.c (revision 3acbec48)
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