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