eac0d20d588e90814492930c37a669f753f67537
[simavr] / simavr / sim / sim_gdb.c
1 /*
2         sim_gdb.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <arpa/inet.h>
25 #include <sys/socket.h>
26 #include <sys/time.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <poll.h>
33 #include <pthread.h>
34 #include "sim_avr.h"
35 #include "avr_eeprom.h"
36
37 typedef struct avr_gdb_t {
38         avr_t * avr;
39         int             listen; // listen socket
40         int             s;              // current gdb connection
41         
42         pthread_t thread;
43
44         uint32_t        query_len;
45         char            query[1024];
46
47         uint32_t        watchmap;
48         struct {
49                 uint32_t        pc;
50                 uint32_t        len;
51                 int kind;
52         } watch[32];
53 } avr_gdb_t;
54
55     // decode line text hex to binary
56 int read_hex_string(const char * src, uint8_t * buffer, int maxlen)
57 {
58     uint8_t * dst = buffer;
59     int ls = 0;
60     uint8_t b = 0;
61     while (*src && maxlen--) {
62         char c = *src++;
63         switch (c) {
64             case 'a' ... 'f':   b = (b << 4) | (c - 'a' + 0xa); break;
65             case 'A' ... 'F':   b = (b << 4) | (c - 'A' + 0xa); break;
66             case '0' ... '9':   b = (b << 4) | (c - '0'); break;
67             default:
68                 if (c > ' ') {
69                     fprintf(stderr, "%s: huh '%c' (%s)\n", __FUNCTION__, c, src);
70                     return -1;
71                 }
72                 continue;
73         }
74         if (ls & 1) {
75             *dst++ = b; b = 0;
76         }
77         ls++;
78     }
79
80     return dst - buffer;
81 }
82
83 static void gdb_send_reply(avr_gdb_t * g, char * cmd)
84 {
85         uint8_t reply[1024];
86         uint8_t * dst = reply;
87         uint8_t check = 0;
88         *dst++ = '$';
89         while (*cmd) {
90                 check += *cmd;
91                 *dst++ = *cmd++;
92         }
93         sprintf((char*)dst, "#%02x", check);
94         printf("%s '%s'\n", __FUNCTION__, reply);
95         send(g->s, reply, dst - reply + 3, 0);
96 }
97
98 static void gdb_send_quick_status(avr_gdb_t * g, uint8_t signal)
99 {
100         char cmd[64];
101
102         sprintf(cmd, "T%02x20:%02x;21:%02x%02x;22:%02x%02x%02x00;",
103                 signal, g->avr->data[R_SREG], 
104                 g->avr->data[R_SPL], g->avr->data[R_SPH],
105                 g->avr->pc & 0xff, (g->avr->pc>>8)&0xff, (g->avr->pc>>16)&0xff);
106         gdb_send_reply(g, cmd);
107 }
108
109 static int gdb_change_breakpoint(avr_gdb_t * g, int set, int kind, uint32_t addr, uint32_t len)
110 {
111         printf("set %d kind %d addr %08x len %d (map %08x)\n", set, kind, addr, len, g->watchmap);
112         if (set) {
113                 if (g->watchmap == 0xffffffff)
114                         return -1;      // map full
115
116                 // check to see if it exists
117                 for (int i = 0; i < 32; i++)
118                         if ((g->watchmap & (1 << i)) && g->watch[i].pc == addr) {
119                                 g->watch[i].len = len;
120                                 return 0;
121                         }
122                 for (int i = 0; i < 32; i++)
123                         if (!(g->watchmap & (1 << i))) {
124                                 g->watchmap |= (1 << i);
125                                 g->watch[i].len = len;
126                                 g->watch[i].pc = addr;
127                                 g->watch[i].kind = kind;
128                                 return 0;
129                         }
130         } else {
131                 for (int i = 0; i < 32; i++)
132                         if ((g->watchmap & (1 << i)) && g->watch[i].pc == addr) {
133                                 g->watchmap &= ~(1 << i);
134                                 g->watch[i].len = 0;
135                                 g->watch[i].pc = 0;
136                                 g->watch[i].kind = 0;
137                                 return 0;
138                         }
139         }
140         return -1;
141 }
142
143 static void gdb_handle_command(avr_gdb_t * g)
144 {
145         avr_t * avr = g->avr;
146         char * cmd = g->query;
147         char rep[1024];
148         uint8_t command = *cmd++;
149         switch (command) {
150                 case '?':
151                         gdb_send_reply(g, "S00");
152                         break;
153                 case 'p': {
154                         unsigned int regi = 0;
155                         sscanf(cmd, "%x", &regi);
156                         switch (regi) {
157                                 case 0 ... 31:
158                                         sprintf(rep, "%02x", g->avr->data[regi]);
159                                         break;
160                                 case 32:
161                                         sprintf(rep, "%02x", g->avr->data[R_SREG]);
162                                         break;
163                                 case 33:
164                                         sprintf(rep, "%02x%02x", g->avr->data[R_SPL], g->avr->data[R_SPH]);
165                                         break;
166                                 case 34:
167                                         sprintf(rep, "%02x%02x%02x00", 
168                                                 g->avr->pc & 0xff, (g->avr->pc>>8)&0xff, (g->avr->pc>>16)&0xff);
169                                         break;
170                         }
171                         gdb_send_reply(g, rep);                 
172                 }       break;
173                 case 'm': {
174                         uint32_t addr, len;
175                         sscanf(cmd, "%x,%x", &addr, &len);
176                         printf("read memory %08x, %08x\n", addr, len);
177                         uint8_t * src = NULL;
178                         if (addr < 0xffff) {
179                                 src = avr->flash + addr;
180                         } else if (addr >= 0x800000 && (addr - 0x800000) <= avr->ramend) {
181                                 src = avr->data + addr - 0x800000;
182                         } else if (addr >= 0x810000 && (addr - 0x810000) <= (16*1024)) {
183                                 avr_eeprom_desc_t ee = {.offset = (addr - 0x810000)};
184                                 avr_ioctl(avr, AVR_IOCTL_EEPROM_GET, &ee);
185                                 if (ee.ee)
186                                         src = ee.ee;
187                                 else
188                                         gdb_send_reply(g, "E01");
189                         } else {
190                                 gdb_send_reply(g, "E01");
191                                 break;
192                         }
193                         char * dst = rep;
194                         while (len--) {
195                                 sprintf(dst, "%02x", *src++);
196                                 dst += 2;
197                         }
198                         *dst = 0;
199                         gdb_send_reply(g, rep);
200                 }       break;
201                 case 'M': {
202                         uint32_t addr, len;
203                         sscanf(cmd, "%x,%x", &addr, &len);
204                         printf("write memory %08x, %08x\n", addr, len);
205                         char * start = strchr(cmd, ':');
206                         if (!start) {
207                                 gdb_send_reply(g, "E01");
208                                 break;
209                         }
210                         if (addr < 0xffff) {
211                                 read_hex_string(start + 1, avr->flash + addr, strlen(start+1));
212                                 gdb_send_reply(g, "OK");                        
213                         } else if (addr >= 0x800000 && (addr - 0x800000) <= avr->ramend) {
214                                 read_hex_string(start + 1, avr->data + addr - 0x800000, strlen(start+1));
215                                 gdb_send_reply(g, "OK");                                                        
216                         } else
217                                 gdb_send_reply(g, "E01");                       
218                 }       break;
219                 case 'c': {
220                         avr->state = cpu_Running;
221                 }       break;
222                 case 's': {
223                         avr->state = cpu_Step;
224                 }       break;
225                 case 'Z': 
226                 case 'z': {
227                         uint32_t kind, addr, len;
228                         sscanf(cmd, "%d,%x,%x", &kind, &addr, &len);
229                         printf("breakbpoint %d, %08x, %08x\n", kind, addr, len);
230                         switch (kind) {
231                                 case 0: // software breakpoint
232                                 case 1: // hardware breakpoint
233                                         if (addr <= avr->flashend) {
234                                                 if (gdb_change_breakpoint(g, command == 'Z', kind, addr, len))
235                                                         gdb_send_reply(g, "E01");
236                                                 else
237                                                         gdb_send_reply(g, "OK");
238                                         } else
239                                                 gdb_send_reply(g, "E01");               // out of flash address
240                                         break;
241                                 case 2: // write watchpoint
242                                 case 3: // read watchpoint
243                                 case 4: // access watchpoint
244                                 default:
245                                         gdb_send_reply(g, "");
246                         }       
247                 }       break;
248                 default:
249                         gdb_send_reply(g, "");
250         }
251 }
252
253 void avr_gdb_processor(avr_t * avr)
254 {
255         if (!avr || !avr->gdb)
256                 return; 
257         avr_gdb_t * g = avr->gdb;
258
259         if (g->watchmap && avr->state == cpu_Running) {
260                 for (int i = 0; i < 32; i++)
261                         if ((g->watchmap & (1 << i)) && g->watch[i].pc == avr->pc) {
262                                 printf("avr_gdb_processor hit breakpoint at %08x\n", avr->pc);
263                                 gdb_send_quick_status(g, 0);
264                                 avr->state = cpu_Stopped;
265                         }               
266         }
267         if (avr->state == cpu_StepDone) {
268                 gdb_send_quick_status(g, 0);
269                 avr->state = cpu_Stopped;
270         }
271         if (avr->gdb->query_len) {
272                 g->query_len = 0;
273         
274         //      printf("avr_gdb_handle_query got a query '%s'\n", g->query);
275                 gdb_handle_command(g);
276         }
277 }
278
279
280 static void * gdb_network_handler(void * param)
281 {
282         avr_gdb_t * g = (avr_gdb_t*)param;
283
284         do {
285                 if (listen(g->listen, 1)) {
286                         perror("gdb_network_handler listen");
287                         sleep(5);
288                         continue;
289                 }
290                 
291                 struct sockaddr_in address = { 0 };
292                 socklen_t ad_len = sizeof(address);
293
294                 g->s = accept(g->listen, (struct sockaddr*)&address, &ad_len);
295
296                 if (g->s == -1) {
297                         perror("gdb_network_handler accept");
298                         sleep(5);
299                         continue;
300                 }
301                 // should make that thread safe... 
302                 g->avr->state = cpu_Stopped;
303                 
304                 do {
305                         fd_set read_set;
306                         FD_ZERO(&read_set);
307                         FD_SET(g->s, &read_set);
308
309                         struct timeval timo = { 1, 0000 };      // short, but not too short interval
310                         /*int ret =*/ select(g->s + 1, &read_set, NULL, NULL, &timo);
311
312                         if (FD_ISSET(g->s, &read_set)) {
313                                 uint8_t buffer[1024];
314                                 
315                                 ssize_t r = recv(g->s, buffer, sizeof(buffer)-1, 0);
316
317                                 if (r == 0) {
318                                         printf("%s connection closed\n", __FUNCTION__);
319                                         break;
320                                 }
321                                 if (r == -1) {
322                                         perror("gdb_network_handler recv");
323                                         break;
324                                 }
325                                 buffer[r] = 0;
326                         //      printf("%s: received %d bytes\n'%s'\n", __FUNCTION__, r, buffer);
327                         //      hdump("gdb", buffer, r);
328
329                                 uint8_t * src = buffer;
330                                 while (*src == '+' || *src == '-')
331                                         src++;
332                                 if (*src == 3) {
333                                         src++;
334                                         g->query[0] = 3;
335                                         g->query_len = 1; // pass it on ?
336                                 }
337                                 if (*src  == '$') {
338                                         // strip checksum
339                                         uint8_t * end = buffer + r - 1;
340                                         while (end > src && *end != '#')
341                                                 *end-- = 0;
342                                         *end = 0;
343                                         src++;
344                                         printf("GDB command = '%s'\n", src);
345
346                                         send(g->s, "+", 1, 0);
347
348                                         strcpy(g->query, (char*)src);
349                                         g->query_len = strlen((char*)src);
350                                 }
351                         }
352                 } while(1);
353                 
354                 close(g->s);
355                         
356         } while(1);
357         
358         return NULL;
359 }
360
361
362 int avr_gdb_init(avr_t * avr)
363 {
364         avr_gdb_t * g = malloc(sizeof(avr_gdb_t));
365         memset(g, 0, sizeof(avr_gdb_t));
366
367         avr->gdb = NULL;
368
369         if ((g->listen = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
370                 fprintf(stderr, "Can't create socket: %s", strerror(errno));
371                 return -1;
372         }
373
374         int i = 1;
375         setsockopt(g->listen, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
376
377         struct sockaddr_in address = { 0 };
378         address.sin_family = AF_INET;
379         address.sin_port = htons (1234);
380
381         if (bind(g->listen, (struct sockaddr *) &address, sizeof(address))) {
382                 fprintf(stderr, "Can not bind socket: %s", strerror(errno));
383                 return -1;
384         }
385         printf("avr_gdb_init listening on port %d\n", 1234);
386         g->avr = avr;
387         avr->gdb = g;
388
389         pthread_create(&g->thread, NULL, gdb_network_handler, g);
390
391         return 0;
392 }