1 /* 2 * PROJECT: ReactOS KD dll - GDB stub 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Base functions for the kernel debugger 5 * COPYRIGHT: Copyright 2021 Jérôme Gardou 6 */ 7 8 #include "kdgdb.h" 9 10 enum reg_name 11 { 12 RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, 13 R8, R9, R10, R11, R12, R13, R14, R15, 14 RIP, 15 EFLAGS, 16 CS, SS, DS, ES, FS, GS, 17 ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7, 18 FCTRL, FSTAT, FTAG, FISEG, FIOFF, FOSEG, FOOFF, FOP 19 }; 20 21 static const unsigned char reg_size[] = 22 { 23 8, 8, 8, 8, 8, 8, 8, 8, 24 8, 8, 8, 8, 8, 8, 8, 8, 25 8, 26 4, 27 4, 4, 4, 4, 4, 4, 28 10, 10, 10, 10, 10, 10, 10, 10, 29 8, 8, 8, 8, 8, 8, 8, 8 30 }; 31 32 static 33 void* 34 ctx_to_reg(CONTEXT* ctx, enum reg_name name) 35 { 36 switch (name) 37 { 38 case RAX: return &ctx->Rax; 39 case RBX: return &ctx->Rbx; 40 case RCX: return &ctx->Rcx; 41 case RDX: return &ctx->Rdx; 42 case RSP: return &ctx->Rsp; 43 case RBP: return &ctx->Rbp; 44 case RSI: return &ctx->Rsi; 45 case RDI: return &ctx->Rdi; 46 case RIP: return &ctx->Rip; 47 case R8: return &ctx->R8; 48 case R9: return &ctx->R9; 49 case R10: return &ctx->R10; 50 case R11: return &ctx->R11; 51 case R12: return &ctx->R12; 52 case R13: return &ctx->R13; 53 case R14: return &ctx->R14; 54 case R15: return &ctx->R15; 55 case EFLAGS: return &ctx->EFlags; 56 case CS: return &ctx->SegCs; 57 case DS: return &ctx->SegSs; 58 case ES: return &ctx->SegEs; 59 case FS: return &ctx->SegFs; 60 case GS: return &ctx->SegGs; 61 case SS: return &ctx->SegSs; 62 } 63 #undef return_reg 64 return 0; 65 } 66 67 static 68 void* 69 thread_to_reg(PETHREAD Thread, enum reg_name reg_name) 70 { 71 static const void* NullValue = NULL; 72 73 #if 0 74 if (Thread->Tcb.TrapFrame) 75 { 76 PKTRAP_FRAME TrapFrame = Thread->Tcb.TrapFrame; 77 78 switch (reg_name) 79 { 80 case RAX: return &TrapFrame->Rax; 81 case RBX: return &TrapFrame->Rbx; 82 case RCX: return &TrapFrame->Rcx; 83 case RDX: return &TrapFrame->Rdx; 84 case RSP: return &TrapFrame->Rsp; 85 case RBP: return &TrapFrame->Rbp; 86 case RSI: return &TrapFrame->Rsi; 87 case RDI: return &TrapFrame->Rdi; 88 case RIP: return &TrapFrame->Rip; 89 case R8: return &TrapFrame->R8; 90 case R9: return &TrapFrame->R9; 91 case R10: return &TrapFrame->R10; 92 case R11: return &TrapFrame->R11; 93 case EFLAGS: return &TrapFrame->EFlags; 94 case CS: return &TrapFrame->SegCs; 95 case DS: return &TrapFrame->SegSs; 96 case ES: return &TrapFrame->SegEs; 97 case FS: return &TrapFrame->SegFs; 98 case GS: return &TrapFrame->SegGs; 99 case SS: return &TrapFrame->SegSs; 100 default: 101 KDDBGPRINT("Unhandled regname: %d.\n", reg_name); 102 } 103 } 104 else 105 #endif 106 if (!Thread->Tcb.InitialStack) 107 { 108 /* Terminated thread ? */ 109 switch (reg_name) 110 { 111 case RSP: 112 case RBP: 113 case RIP: 114 KDDBGPRINT("Returning NULL for register %d.\n", reg_name); 115 return &NullValue; 116 default: 117 return NULL; 118 } 119 } 120 else 121 { 122 switch(reg_name) 123 { 124 case RSP: return &Thread->Tcb.KernelStack; 125 case RIP: 126 { 127 PULONG_PTR Rsp = Thread->Tcb.KernelStack; 128 return &Rsp[3]; 129 } 130 case RBP: 131 { 132 PULONG_PTR Rsp = Thread->Tcb.KernelStack; 133 return &Rsp[4]; 134 } 135 default: 136 return NULL; 137 } 138 } 139 140 return NULL; 141 } 142 143 KDSTATUS 144 gdb_send_registers(void) 145 { 146 CHAR RegisterStr[17]; 147 UCHAR* RegisterPtr; 148 unsigned short i; 149 unsigned short size; 150 151 start_gdb_packet(); 152 153 KDDBGPRINT("Sending registers of thread %" PRIxPTR ".\n", gdb_dbg_tid); 154 KDDBGPRINT("Current thread_id: %p.\n", PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)); 155 if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) || 156 gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)) 157 { 158 for (i = 0; i < 24; i++) 159 { 160 RegisterPtr = ctx_to_reg(&CurrentContext, i); 161 size = reg_size[i] * 2; 162 RegisterStr[size] = 0; 163 while (size) 164 { 165 size--; 166 RegisterStr[size] = hex_chars[RegisterPtr[size/2] & 0xF]; 167 size--; 168 RegisterStr[size] = hex_chars[RegisterPtr[size/2] >> 4]; 169 } 170 171 send_gdb_partial_packet(RegisterStr); 172 } 173 } 174 else 175 { 176 PETHREAD DbgThread; 177 178 DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid); 179 180 if (DbgThread == NULL) 181 { 182 /* Thread is dead */ 183 send_gdb_partial_packet("E03"); 184 return finish_gdb_packet(); 185 } 186 187 for (i = 0; i < 24; i++) 188 { 189 RegisterPtr = thread_to_reg(DbgThread, i); 190 size = reg_size[i] * 2; 191 RegisterStr[size] = 0; 192 193 while (size) 194 { 195 if (RegisterPtr) 196 { 197 size--; 198 RegisterStr[size] = hex_chars[RegisterPtr[size/2] & 0xF]; 199 size--; 200 RegisterStr[size] = hex_chars[RegisterPtr[size/2] >> 4]; 201 } 202 else 203 { 204 size--; 205 RegisterStr[size] = 'x'; 206 size--; 207 RegisterStr[size] = 'x'; 208 } 209 } 210 211 send_gdb_partial_packet(RegisterStr); 212 } 213 } 214 215 return finish_gdb_packet(); 216 } 217 218 KDSTATUS 219 gdb_send_register(void) 220 { 221 enum reg_name reg_name; 222 void *ptr; 223 224 /* Get the GDB register name (gdb_input = "pXX") */ 225 reg_name = (hex_value(gdb_input[1]) << 4) | hex_value(gdb_input[2]); 226 227 if (((gdb_dbg_pid == 0) && (gdb_dbg_tid == 0)) || 228 gdb_tid_to_handle(gdb_dbg_tid) == PsGetThreadId((PETHREAD)(ULONG_PTR)CurrentStateChange.Thread)) 229 { 230 /* We can get it from the context of the current exception */ 231 ptr = ctx_to_reg(&CurrentContext, reg_name); 232 } 233 else 234 { 235 PETHREAD DbgThread; 236 237 DbgThread = find_thread(gdb_dbg_pid, gdb_dbg_tid); 238 239 if (DbgThread == NULL) 240 { 241 /* Thread is dead */ 242 return send_gdb_packet("E03"); 243 } 244 245 ptr = thread_to_reg(DbgThread, reg_name); 246 } 247 248 if (!ptr) 249 { 250 unsigned char size = reg_size[reg_name]; 251 start_gdb_packet(); 252 while (size--) 253 send_gdb_partial_packet("xx"); 254 return finish_gdb_packet(); 255 } 256 else 257 { 258 KDDBGPRINT("KDDBG : Sending registers as memory.\n"); 259 return send_gdb_memory(ptr, reg_size[reg_name]); 260 } 261 } 262 263 264