1 /* 2 * COPYRIGHT: GPL, see COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: drivers/base/kddll/gdb_send.c 5 * PURPOSE: Base functions for the kernel debugger. 6 */ 7 8 #include "kdgdb.h" 9 10 /* LOCALS *********************************************************************/ 11 const char hex_chars[] = "0123456789abcdef"; 12 static CHAR currentChecksum = 0; 13 14 /* PRIVATE FUNCTIONS **********************************************************/ 15 static 16 char* 17 exception_code_to_gdb(NTSTATUS code, char* out) 18 { 19 unsigned char SigVal; 20 21 switch (code) 22 { 23 case STATUS_INTEGER_DIVIDE_BY_ZERO: 24 SigVal = 8; /* divide by zero */ 25 break; 26 case STATUS_SINGLE_STEP: 27 case STATUS_BREAKPOINT: 28 SigVal = 5; /* breakpoint */ 29 break; 30 case STATUS_INTEGER_OVERFLOW: 31 case STATUS_ARRAY_BOUNDS_EXCEEDED: 32 SigVal = 16; /* bound instruction */ 33 break; 34 case STATUS_ILLEGAL_INSTRUCTION: 35 SigVal = 4; /* Invalid opcode */ 36 break; 37 case STATUS_STACK_OVERFLOW: 38 case STATUS_DATATYPE_MISALIGNMENT: 39 case STATUS_ACCESS_VIOLATION: 40 SigVal = 11; /* access violation */ 41 break; 42 default: 43 SigVal = 7; /* "software generated" */ 44 } 45 *out++ = hex_chars[(SigVal >> 4) & 0xf]; 46 *out++ = hex_chars[SigVal & 0xf]; 47 return out; 48 } 49 50 /* GLOBAL FUNCTIONS ***********************************************************/ 51 void 52 start_gdb_packet(void) 53 { 54 /* Start the start byte and begin checksum calculation */ 55 KdpSendByte('$'); 56 currentChecksum = 0; 57 } 58 59 void 60 send_gdb_partial_packet(_In_ const CHAR* Buffer) 61 { 62 const CHAR* ptr = Buffer; 63 64 /* Update check sum and send */ 65 while (*ptr) 66 { 67 currentChecksum += *ptr; 68 KdpSendByte(*ptr++); 69 } 70 } 71 72 73 KDSTATUS 74 finish_gdb_packet(void) 75 { 76 UCHAR ack; 77 KDSTATUS Status; 78 79 /* Send finish byte and append checksum */ 80 KdpSendByte('#'); 81 KdpSendByte(hex_chars[(currentChecksum >> 4) & 0xf]); 82 KdpSendByte(hex_chars[currentChecksum & 0xf]); 83 84 /* Wait for acknowledgement */ 85 Status = KdpReceiveByte(&ack); 86 87 if (Status != KdPacketReceived) 88 { 89 KD_DEBUGGER_NOT_PRESENT = TRUE; 90 return Status; 91 } 92 93 if (ack != '+') 94 return KdPacketNeedsResend; 95 96 return KdPacketReceived; 97 } 98 99 KDSTATUS 100 send_gdb_packet(_In_ const CHAR* Buffer) 101 { 102 start_gdb_packet(); 103 send_gdb_partial_packet(Buffer); 104 return finish_gdb_packet(); 105 } 106 107 ULONG 108 send_gdb_partial_binary( 109 _In_ const VOID* Buffer, 110 _In_ size_t Length) 111 { 112 const UCHAR* ptr = Buffer; 113 ULONG Sent = Length; 114 115 while(Length--) 116 { 117 UCHAR Byte = *ptr++; 118 119 switch (Byte) 120 { 121 case 0x7d: 122 case 0x23: 123 case 0x24: 124 case 0x2a: 125 currentChecksum += 0x7d; 126 KdpSendByte(0x7d); 127 Byte ^= 0x20; 128 Sent++; 129 /* Fall-through */ 130 default: 131 currentChecksum += Byte; 132 KdpSendByte(Byte); 133 } 134 } 135 136 return Sent; 137 } 138 139 void 140 send_gdb_partial_memory( 141 _In_ const VOID* Buffer, 142 _In_ size_t Length) 143 { 144 const UCHAR* ptr = Buffer; 145 CHAR gdb_out[3]; 146 147 gdb_out[2] = '\0'; 148 149 while(Length--) 150 { 151 gdb_out[0] = hex_chars[(*ptr >> 4) & 0xf]; 152 gdb_out[1] = hex_chars[*ptr++ & 0xf]; 153 send_gdb_partial_packet(gdb_out); 154 } 155 } 156 157 KDSTATUS 158 send_gdb_memory( 159 _In_ const VOID* Buffer, 160 _In_ size_t Length) 161 { 162 start_gdb_packet(); 163 send_gdb_partial_memory(Buffer, Length); 164 return finish_gdb_packet(); 165 } 166 167 KDSTATUS 168 gdb_send_debug_io( 169 _In_ PSTRING String, 170 _In_ BOOLEAN WithPrefix) 171 { 172 CHAR gdb_out[3]; 173 CHAR* ptr = String->Buffer; 174 USHORT Length = String->Length; 175 176 gdb_out[2] = '\0'; 177 178 start_gdb_packet(); 179 180 if (WithPrefix) 181 { 182 send_gdb_partial_packet("O"); 183 } 184 185 /* Send the data */ 186 while (Length--) 187 { 188 gdb_out[0] = hex_chars[(*ptr >> 4) & 0xf]; 189 gdb_out[1] = hex_chars[*ptr++ & 0xf]; 190 send_gdb_partial_packet(gdb_out); 191 } 192 193 return finish_gdb_packet(); 194 } 195 196 KDSTATUS 197 gdb_send_exception() 198 { 199 char gdb_out[1024]; 200 char* ptr = gdb_out; 201 PETHREAD Thread = (PETHREAD)(ULONG_PTR)CurrentStateChange.Thread; 202 203 /* Report to GDB */ 204 *ptr++ = 'T'; 205 206 if (CurrentStateChange.NewState == DbgKdExceptionStateChange) 207 { 208 EXCEPTION_RECORD64* ExceptionRecord = &CurrentStateChange.u.Exception.ExceptionRecord; 209 ptr = exception_code_to_gdb(ExceptionRecord->ExceptionCode, ptr); 210 } 211 else 212 ptr += sprintf(ptr, "05"); 213 214 if (CurrentStateChange.NewState == DbgKdLoadSymbolsStateChange) 215 ptr += sprintf(ptr, "library:"); 216 217 #if MONOPROCESS 218 ptr += sprintf(ptr, "thread:%" PRIxPTR ";", 219 handle_to_gdb_tid(PsGetThreadId(Thread))); 220 #else 221 ptr += sprintf(ptr, "thread:p%" PRIxPTR ".%" PRIxPTR ";", 222 handle_to_gdb_pid(PsGetThreadProcessId(Thread)), 223 handle_to_gdb_tid(PsGetThreadId(Thread))); 224 #endif 225 226 ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor); 227 return send_gdb_packet(gdb_out); 228 } 229 230 void 231 send_gdb_ntstatus( 232 _In_ NTSTATUS Status) 233 { 234 /* Just build a EXX packet and send it */ 235 char gdb_out[4]; 236 gdb_out[0] = 'E'; 237 exception_code_to_gdb(Status, &gdb_out[1]); 238 gdb_out[3] = '\0'; 239 send_gdb_packet(gdb_out); 240 } 241