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