1 /*
2  * Copyright (c) 2011 Peter Zotov <whitequark@whitequark.org>
3  * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4  */
5 
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <stdint.h>
10 
11 #if defined(_WIN32)
12 #include <win32_socket.h>
13 #else
14 #include <unistd.h>
15 #include <sys/poll.h>
16 #endif
17 
18 #include "gdb-remote.h"
19 
20 static const char hex[] = "0123456789abcdef";
21 
gdb_send_packet(int fd,char * data)22 int gdb_send_packet(int fd, char* data) {
23     unsigned int data_length = (unsigned int)strlen(data);
24     int length = data_length + 4;
25     char* packet = malloc(length); // '$' data (hex) '#' cksum (hex)
26 
27     memset(packet, 0, length);
28 
29     packet[0] = '$';
30 
31     uint8_t cksum = 0;
32 
33     for (unsigned int i = 0; i < data_length; i++) {
34         packet[i + 1] = data[i];
35         cksum += data[i];
36     }
37 
38     packet[length - 3] = '#';
39     packet[length - 2] = hex[cksum >> 4];
40     packet[length - 1] = hex[cksum & 0xf];
41 
42     while (1) {
43         if (write(fd, packet, length) != length) {
44             free(packet);
45             return(-2);
46         }
47 
48         char ack;
49 
50         if (read(fd, &ack, 1) != 1) {
51             free(packet);
52             return(-2);
53         }
54 
55         if (ack == '+') {
56             free(packet);
57             return(0);
58         }
59     }
60 }
61 
62 #define ALLOC_STEP 1024
63 
gdb_recv_packet(int fd,char ** buffer)64 int gdb_recv_packet(int fd, char** buffer) {
65     unsigned packet_size = ALLOC_STEP + 1, packet_idx = 0;
66     uint8_t cksum = 0;
67     char recv_cksum[3] = {0};
68     char* packet_buffer = malloc(packet_size);
69     unsigned state;
70 
71     if (packet_buffer == NULL) {
72         return(-2);
73     }
74 
75 start:
76     state = 0;
77     packet_idx = 0;
78     /*
79      * 0: waiting $
80      * 1: data, waiting #
81      * 2: cksum 1
82      * 3: cksum 2
83      * 4: fin
84      */
85 
86     char c;
87 
88     while (state != 4) {
89         if (read(fd, &c, 1) != 1) {
90             free(packet_buffer);
91             return(-2);
92         }
93 
94         switch (state) {
95         case 0:
96 
97             if (c != '$') { /* ignore */
98             } else {
99                 state = 1;
100             }
101 
102             break;
103 
104         case 1:
105 
106             if (c == '#') {
107                 state = 2;
108             } else {
109                 packet_buffer[packet_idx++] = c;
110                 cksum += c;
111 
112                 if (packet_idx == packet_size) {
113                     packet_size += ALLOC_STEP;
114                     void* p = realloc(packet_buffer, packet_size);
115 
116                     if (p != NULL) {
117                         packet_buffer = p;
118                     } else {
119                         free(packet_buffer);
120                         return(-2);
121                     }
122                 }
123             }
124 
125             break;
126 
127         case 2:
128             recv_cksum[0] = c;
129             state = 3;
130             break;
131 
132         case 3:
133             recv_cksum[1] = c;
134             state = 4;
135             break;
136         }
137     }
138 
139     uint8_t recv_cksum_int = strtoul(recv_cksum, NULL, 16);
140 
141     if (recv_cksum_int != cksum) {
142         char nack = '-';
143 
144         if (write(fd, &nack, 1) != 1) {
145             free(packet_buffer);
146             return(-2);
147         }
148 
149         goto start;
150     } else {
151         char ack = '+';
152 
153         if (write(fd, &ack, 1) != 1) {
154             free(packet_buffer);
155             return(-2);
156         }
157     }
158 
159     packet_buffer[packet_idx] = 0;
160     *buffer = packet_buffer;
161 
162     return(packet_idx);
163 }
164 
165 /*
166  * Here we skip any characters which are not \x03, GDB interrupt.
167  * As we use the mode with ACK, in a (very unlikely) situation of a packet lost
168  * because of this skipping, it will be resent anyway.
169  */
gdb_check_for_interrupt(int fd)170 int gdb_check_for_interrupt(int fd) {
171     struct pollfd pfd;
172     pfd.fd = fd;
173     pfd.events = POLLIN;
174 
175     if (poll(&pfd, 1, 0) != 0) {
176         char c;
177 
178         if (read(fd, &c, 1) != 1) {
179             return(-2);
180         }
181 
182         if (c == '\x03') {
183             return(1); // ^C
184         }
185     }
186 
187     return(0);
188 }
189