1 /* MSPDebug - debugging tool for MSP430 MCUs
2 * Copyright (C) 2009-2011 Daniel Beer
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <sys/time.h>
22 #include <unistd.h>
23 #include <string.h>
24
25 #include "sockets.h"
26 #include "gdb_proto.h"
27 #include "output.h"
28 #include "util.h"
29
gdb_init(struct gdb_data * data,int sock)30 void gdb_init(struct gdb_data *data, int sock)
31 {
32 data->sock = sock;
33 data->error = 0;
34 data->head = 0;
35 data->tail = 0;
36 data->outlen = 0;
37 }
38
gdb_printf(struct gdb_data * data,const char * fmt,...)39 void gdb_printf(struct gdb_data *data, const char *fmt, ...)
40 {
41 va_list ap;
42 int len;
43
44 va_start(ap, fmt);
45 len = vsnprintf(data->outbuf + data->outlen,
46 sizeof(data->outbuf) - data->outlen,
47 fmt, ap);
48 va_end(ap);
49
50 data->outlen += len;
51 }
52
53 /* Returns -1 for error, 0 for timeout, >0 if data received. */
gdb_read(struct gdb_data * data,int timeout_ms)54 static int gdb_read(struct gdb_data *data, int timeout_ms)
55 {
56 int was_timeout;
57 int len = sockets_recv(data->sock, data->xbuf, sizeof(data->xbuf), 0,
58 timeout_ms, &was_timeout);
59
60 if (was_timeout)
61 return 0;
62
63 if (len < 0) {
64 data->error = 1;
65 pr_error("gdb: recv");
66 return -1;
67 }
68
69 if (!len) {
70 data->error = 1;
71 printc("Connection closed\n");
72 return -1;
73 }
74
75 data->head = 0;
76 data->tail = len;
77 return len;
78 }
79
gdb_peek(struct gdb_data * data,int timeout_ms)80 int gdb_peek(struct gdb_data *data, int timeout_ms)
81 {
82 if (data->head == data->tail)
83 return gdb_read(data, timeout_ms);
84
85 return data->head != data->tail;
86 }
87
gdb_getc(struct gdb_data * data)88 int gdb_getc(struct gdb_data *data)
89 {
90 int c;
91
92 /* If the buffer is empty, receive some more data */
93 if (data->head == data->tail && gdb_read(data, -1) <= 0)
94 return -1;
95
96 c = data->xbuf[data->head];
97 data->head++;
98
99 return c;
100 }
101
gdb_flush(struct gdb_data * data)102 static int gdb_flush(struct gdb_data *data)
103 {
104 if (sockets_send(data->sock, data->outbuf, data->outlen, 0) < 0) {
105 data->error = 1;
106 pr_error("gdb: flush");
107 return -1;
108 }
109
110 data->outlen = 0;
111 return 0;
112 }
113
gdb_flush_ack(struct gdb_data * data)114 int gdb_flush_ack(struct gdb_data *data)
115 {
116 int c;
117
118 #ifdef DEBUG_GDB
119 printc("-> %s\n", data->outbuf);
120 #endif
121 data->outbuf[data->outlen] = 0;
122
123 do {
124 if (sockets_send(data->sock, data->outbuf,
125 data->outlen, 0) < 0) {
126 data->error = 1;
127 pr_error("gdb: flush_ack");
128 return -1;
129 }
130
131 do {
132 c = gdb_getc(data);
133 if (c < 0)
134 return -1;
135 } while (c != '+' && c != '-');
136 } while (c != '+');
137
138 data->outlen = 0;
139 return 0;
140 }
141
gdb_packet_start(struct gdb_data * data)142 void gdb_packet_start(struct gdb_data *data)
143 {
144 gdb_printf(data, "$");
145 }
146
gdb_packet_end(struct gdb_data * data)147 void gdb_packet_end(struct gdb_data *data)
148 {
149 int i;
150 int c = 0;
151
152 for (i = 1; i < data->outlen; i++)
153 c = (c + data->outbuf[i]) & 0xff;
154 gdb_printf(data, "#%02x", c);
155 }
156
gdb_send(struct gdb_data * data,const char * msg)157 int gdb_send(struct gdb_data *data, const char *msg)
158 {
159 gdb_packet_start(data);
160 gdb_printf(data, "%s", msg);
161 gdb_packet_end(data);
162 return gdb_flush_ack(data);
163 }
164
gdb_read_packet(struct gdb_data * data,char * buf)165 int gdb_read_packet(struct gdb_data *data, char *buf)
166 {
167 int c;
168 int len = 0;
169 int cksum_calc = 0;
170 int cksum_recv = 0;
171
172 /* Wait for packet start */
173 do {
174 c = gdb_getc(data);
175 if (c < 0)
176 return -1;
177 } while (c != '$');
178
179 /* Read packet payload */
180 while (len + 1 < GDB_BUF_SIZE) {
181 c = gdb_getc(data);
182 if (c < 0)
183 return -1;
184 if (c == '#')
185 break;
186
187 buf[len++] = c;
188 cksum_calc = (cksum_calc + c) & 0xff;
189 }
190 buf[len] = 0;
191
192 /* Read packet checksum */
193 c = gdb_getc(data);
194 if (c < 0)
195 return -1;
196 cksum_recv = hexval(c);
197 c = gdb_getc(data);
198 if (c < 0)
199 return -1;
200 cksum_recv = (cksum_recv << 4) | hexval(c);
201
202 #ifdef DEBUG_GDB
203 printc("<- $%s#%02x\n", buf, cksum_recv);
204 #endif
205
206 if (cksum_recv != cksum_calc) {
207 printc_err("gdb: bad checksum (calc = 0x%02x, "
208 "recv = 0x%02x)\n", cksum_calc, cksum_recv);
209 printc_err("gdb: packet data was: %s\n", buf);
210 gdb_printf(data, "-");
211 if (gdb_flush(data) < 0)
212 return -1;
213 return 0;
214 }
215
216 /* Send acknowledgement */
217 gdb_printf(data, "+");
218 if (gdb_flush(data) < 0)
219 return -1;
220
221 return len;
222 }
223