xref: /reactos/drivers/base/kdgdb/gdb_send.c (revision 321bcc05)
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 
13 /* PRIVATE FUNCTIONS **********************************************************/
14 static
15 char*
16 exception_code_to_gdb(NTSTATUS code, char* out)
17 {
18     unsigned char SigVal;
19 
20     switch (code)
21     {
22     case STATUS_INTEGER_DIVIDE_BY_ZERO:
23         SigVal = 8; /* divide by zero */
24         break;
25     case STATUS_SINGLE_STEP:
26     case STATUS_BREAKPOINT:
27         SigVal = 5; /* breakpoint */
28         break;
29     case STATUS_INTEGER_OVERFLOW:
30     case STATUS_ARRAY_BOUNDS_EXCEEDED:
31         SigVal = 16; /* bound instruction */
32         break;
33     case STATUS_ILLEGAL_INSTRUCTION:
34         SigVal = 4; /* Invalid opcode */
35         break;
36     case STATUS_STACK_OVERFLOW:
37     case STATUS_DATATYPE_MISALIGNMENT:
38     case STATUS_ACCESS_VIOLATION:
39         SigVal = 11; /* access violation */
40         break;
41     default:
42         SigVal = 7; /* "software generated" */
43     }
44     *out++ = hex_chars[(SigVal >> 4) & 0xf];
45     *out++ = hex_chars[SigVal & 0xf];
46     return out;
47 }
48 
49 /* GLOBAL FUNCTIONS ***********************************************************/
50 void
51 send_gdb_packet(_In_ CHAR* Buffer)
52 {
53     UCHAR ack;
54 
55     do {
56         CHAR* ptr = Buffer;
57         CHAR check_sum = 0;
58 
59         KdpSendByte('$');
60 
61         /* Calculate checksum */
62         check_sum = 0;
63         while (*ptr)
64         {
65             check_sum += *ptr;
66             KdpSendByte(*ptr++);
67         }
68 
69         /* append it */
70         KdpSendByte('#');
71         KdpSendByte(hex_chars[(check_sum >> 4) & 0xf]);
72         KdpSendByte(hex_chars[check_sum & 0xf]);
73 
74         /* Wait for acknowledgement */
75         if (KdpReceiveByte(&ack) != KdPacketReceived)
76         {
77             KD_DEBUGGER_NOT_PRESENT = TRUE;
78             break;
79         }
80     } while (ack != '+');
81 }
82 
83 void
84 send_gdb_memory(
85     _In_ VOID* Buffer,
86     _In_ size_t Length)
87 {
88     UCHAR ack;
89 
90     do {
91         CHAR* ptr = Buffer;
92         CHAR check_sum = 0;
93         size_t len = Length;
94         CHAR Byte;
95 
96         KdpSendByte('$');
97 
98         /* Send the data */
99         check_sum = 0;
100         while (len--)
101         {
102             Byte = hex_chars[(*ptr >> 4) & 0xf];
103             KdpSendByte(Byte);
104             check_sum += Byte;
105             Byte = hex_chars[*ptr++ & 0xf];
106             KdpSendByte(Byte);
107             check_sum += Byte;
108         }
109 
110         /* append check sum */
111         KdpSendByte('#');
112         KdpSendByte(hex_chars[(check_sum >> 4) & 0xf]);
113         KdpSendByte(hex_chars[check_sum & 0xf]);
114 
115         /* Wait for acknowledgement */
116         if (KdpReceiveByte(&ack) != KdPacketReceived)
117         {
118             KD_DEBUGGER_NOT_PRESENT = TRUE;
119             break;
120         }
121     } while (ack != '+');
122 }
123 
124 void
125 gdb_send_debug_io(
126     _In_ PSTRING String)
127 {
128     UCHAR ack;
129 
130     do {
131         CHAR* ptr = String->Buffer;
132         CHAR check_sum;
133         USHORT Length = String->Length;
134         CHAR Byte;
135 
136         KdpSendByte('$');
137 
138         KdpSendByte('O');
139 
140         /* Send the data */
141         check_sum = 'O';
142         while (Length--)
143         {
144             Byte = hex_chars[(*ptr >> 4) & 0xf];
145             KdpSendByte(Byte);
146             check_sum += Byte;
147             Byte = hex_chars[*ptr++ & 0xf];
148             KdpSendByte(Byte);
149             check_sum += Byte;
150         }
151 
152         /* append check sum */
153         KdpSendByte('#');
154         KdpSendByte(hex_chars[(check_sum >> 4) & 0xf]);
155         KdpSendByte(hex_chars[check_sum & 0xf]);
156 
157         /* Wait for acknowledgement */
158         if (KdpReceiveByte(&ack) != KdPacketReceived)
159         {
160             KD_DEBUGGER_NOT_PRESENT = TRUE;
161             break;
162         }
163     } while (ack != '+');
164 }
165 
166 void
167 gdb_send_exception(void)
168 {
169     char gdb_out[1024];
170     char* ptr = gdb_out;
171     PETHREAD Thread = (PETHREAD)(ULONG_PTR)CurrentStateChange.Thread;
172 
173     /* Report to GDB */
174     *ptr++ = 'T';
175 
176     if (CurrentStateChange.NewState == DbgKdExceptionStateChange)
177     {
178         EXCEPTION_RECORD64* ExceptionRecord = &CurrentStateChange.u.Exception.ExceptionRecord;
179         ptr = exception_code_to_gdb(ExceptionRecord->ExceptionCode, ptr);
180     }
181     else
182         ptr += sprintf(ptr, "05");
183 
184     ptr += sprintf(ptr, "thread:p%" PRIxPTR ".%" PRIxPTR ";",
185         handle_to_gdb_pid(PsGetThreadProcessId(Thread)),
186         handle_to_gdb_tid(PsGetThreadId(Thread)));
187     ptr += sprintf(ptr, "core:%x;", CurrentStateChange.Processor);
188     send_gdb_packet(gdb_out);
189 }
190 
191 void
192 send_gdb_ntstatus(
193     _In_ NTSTATUS Status)
194 {
195     /* Just build a EXX packet and send it */
196     char gdb_out[4];
197     gdb_out[0] = 'E';
198     exception_code_to_gdb(Status, &gdb_out[1]);
199     gdb_out[3] = '\0';
200     send_gdb_packet(gdb_out);
201 }
202