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 #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 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 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