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