first part of single stepping support
[qemu] / gdbstub.c
1 /*
2  * gdb server stub
3  * 
4  * Copyright (c) 2003 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
28 #include <signal.h>
29
30 #include "config.h"
31 #ifdef TARGET_I386
32 #include "cpu-i386.h"
33 #endif
34 #ifdef TARGET_ARM
35 #include "cpu-arm.h"
36 #endif
37 #include "thunk.h"
38 #include "exec.h"
39
40 //#define DEBUG_GDB
41
42 int gdbstub_fd = -1;
43
44 /* return 0 if OK */
45 static int gdbstub_open(int port)
46 {
47     struct sockaddr_in sockaddr;
48     socklen_t len;
49     int fd, val, ret;
50
51     fd = socket(PF_INET, SOCK_STREAM, 0);
52     if (fd < 0) {
53         perror("socket");
54         return -1;
55     }
56
57     /* allow fast reuse */
58     val = 1;
59     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
60
61     sockaddr.sin_family = AF_INET;
62     sockaddr.sin_port = htons(port);
63     sockaddr.sin_addr.s_addr = 0;
64     ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
65     if (ret < 0) {
66         perror("bind");
67         return -1;
68     }
69     ret = listen(fd, 0);
70     if (ret < 0) {
71         perror("listen");
72         return -1;
73     }
74     
75     /* now wait for one connection */
76     for(;;) {
77         len = sizeof(sockaddr);
78         gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len);
79         if (gdbstub_fd < 0 && errno != EINTR) {
80             perror("accept");
81             return -1;
82         } else if (gdbstub_fd >= 0) {
83             break;
84         }
85     }
86     
87     /* set short latency */
88     val = 1;
89     setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
90     return 0;
91 }
92
93 static int get_char(void)
94 {
95     uint8_t ch;
96     int ret;
97
98     for(;;) {
99         ret = read(gdbstub_fd, &ch, 1);
100         if (ret < 0) {
101             if (errno != EINTR && errno != EAGAIN)
102                 return -1;
103         } else if (ret == 0) {
104             return -1;
105         } else {
106             break;
107         }
108     }
109     return ch;
110 }
111
112 static void put_buffer(const uint8_t *buf, int len)
113 {
114     int ret;
115
116     while (len > 0) {
117         ret = write(gdbstub_fd, buf, len);
118         if (ret < 0) {
119             if (errno != EINTR && errno != EAGAIN)
120                 return;
121         } else {
122             buf += ret;
123             len -= ret;
124         }
125     }
126 }
127
128 static inline int fromhex(int v)
129 {
130     if (v >= '0' && v <= '9')
131         return v - '0';
132     else if (v >= 'A' && v <= 'F')
133         return v - 'A' + 10;
134     else if (v >= 'a' && v <= 'f')
135         return v - 'a' + 10;
136     else
137         return 0;
138 }
139
140 static inline int tohex(int v)
141 {
142     if (v < 10)
143         return v + '0';
144     else
145         return v - 10 + 'a';
146 }
147
148 static void memtohex(char *buf, const uint8_t *mem, int len)
149 {
150     int i, c;
151     char *q;
152     q = buf;
153     for(i = 0; i < len; i++) {
154         c = mem[i];
155         *q++ = tohex(c >> 4);
156         *q++ = tohex(c & 0xf);
157     }
158     *q = '\0';
159 }
160
161 static void hextomem(uint8_t *mem, const char *buf, int len)
162 {
163     int i;
164
165     for(i = 0; i < len; i++) {
166         mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
167         buf += 2;
168     }
169 }
170
171 /* return -1 if error or EOF */
172 static int get_packet(char *buf, int buf_size)
173 {
174     int ch, len, csum, csum1;
175     char reply[1];
176     
177     for(;;) {
178         for(;;) {
179             ch = get_char();
180             if (ch < 0)
181                 return -1;
182             if (ch == '$')
183                 break;
184         }
185         len = 0;
186         csum = 0;
187         for(;;) {
188             ch = get_char();
189             if (ch < 0)
190                 return -1;
191             if (ch == '#')
192                 break;
193             if (len > buf_size - 1)
194                 return -1;
195             buf[len++] = ch;
196             csum += ch;
197         }
198         buf[len] = '\0';
199         ch = get_char();
200         if (ch < 0)
201             return -1;
202         csum1 = fromhex(ch) << 4;
203         ch = get_char();
204         if (ch < 0)
205             return -1;
206         csum1 |= fromhex(ch);
207         if ((csum & 0xff) != csum1) {
208             reply[0] = '-';
209             put_buffer(reply, 1);
210         } else {
211             reply[0] = '+';
212             put_buffer(reply, 1);
213             break;
214         }
215     }
216 #ifdef DEBUG_GDB
217     printf("command='%s'\n", buf);
218 #endif
219     return len;
220 }
221
222 /* return -1 if error, 0 if OK */
223 static int put_packet(char *buf)
224 {
225     char buf1[3];
226     int len, csum, ch, i;
227
228 #ifdef DEBUG_GDB
229     printf("reply='%s'\n", buf);
230 #endif
231
232     for(;;) {
233         buf1[0] = '$';
234         put_buffer(buf1, 1);
235         len = strlen(buf);
236         put_buffer(buf, len);
237         csum = 0;
238         for(i = 0; i < len; i++) {
239             csum += buf[i];
240         }
241         buf1[0] = '#';
242         buf1[1] = tohex((csum >> 4) & 0xf);
243         buf1[2] = tohex((csum) & 0xf);
244
245         put_buffer(buf1, 3);
246
247         ch = get_char();
248         if (ch < 0)
249             return -1;
250         if (ch == '+')
251             break;
252     }
253     return 0;
254 }
255
256 static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
257 {
258     int l, flags;
259     uint32_t page;
260
261     while (len > 0) {
262         page = addr & TARGET_PAGE_MASK;
263         l = (page + TARGET_PAGE_SIZE) - addr;
264         if (l > len)
265             l = len;
266         flags = page_get_flags(page);
267         if (!(flags & PAGE_VALID))
268             return -1;
269         if (is_write) {
270             if (!(flags & PAGE_WRITE))
271                 return -1;
272             memcpy((uint8_t *)addr, buf, l);
273         } else {
274             if (!(flags & PAGE_READ))
275                 return -1;
276             memcpy(buf, (uint8_t *)addr, l);
277         }
278         len -= l;
279         buf += l;
280         addr += l;
281     }
282     return 0;
283 }
284
285 /* port = 0 means default port */
286 int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
287 {
288     CPUState *env;
289     const char *p;
290     int ret, ch, nb_regs, i, type;
291     char buf[4096];
292     uint8_t mem_buf[2000];
293     uint32_t *registers;
294     uint32_t addr, len;
295     
296     printf("Waiting gdb connection on port %d\n", port);
297     if (gdbstub_open(port) < 0)
298         return -1;
299     printf("Connected\n");
300     for(;;) {
301         ret = get_packet(buf, sizeof(buf));
302         if (ret < 0)
303             break;
304         p = buf;
305         ch = *p++;
306         switch(ch) {
307         case '?':
308             snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
309             put_packet(buf);
310             break;
311         case 'c':
312             if (*p != '\0') {
313                 addr = strtoul(p, (char **)&p, 16);
314                 env = cpu_gdbstub_get_env(opaque);
315 #if defined(TARGET_I386)
316                 env->eip = addr;
317 #endif
318             }
319             ret = main_loop(opaque);
320             if (ret == EXCP_DEBUG)
321                 ret = SIGTRAP;
322             else
323                 ret = 0;
324             snprintf(buf, sizeof(buf), "S%02x", ret);
325             put_packet(buf);
326             break;
327         case 's':
328             env = cpu_gdbstub_get_env(opaque);
329             if (*p != '\0') {
330                 addr = strtoul(p, (char **)&p, 16);
331 #if defined(TARGET_I386)
332                 env->eip = addr;
333 #endif
334             }
335             cpu_single_step(env, 1);
336             ret = main_loop(opaque);
337             cpu_single_step(env, 0);
338             if (ret == EXCP_DEBUG)
339                 ret = SIGTRAP;
340             else
341                 ret = 0;
342             snprintf(buf, sizeof(buf), "S%02x", ret);
343             put_packet(buf);
344             break;
345         case 'g':
346             env = cpu_gdbstub_get_env(opaque);
347             registers = (void *)mem_buf;
348 #if defined(TARGET_I386)
349             for(i = 0; i < 8; i++) {
350                 registers[i] = tswapl(env->regs[i]);
351             }
352             registers[8] = env->eip;
353             registers[9] = env->eflags;
354             registers[10] = env->segs[R_CS].selector;
355             registers[11] = env->segs[R_SS].selector;
356             registers[12] = env->segs[R_DS].selector;
357             registers[13] = env->segs[R_ES].selector;
358             registers[14] = env->segs[R_FS].selector;
359             registers[15] = env->segs[R_GS].selector;
360             nb_regs = 16;
361 #endif
362             memtohex(buf, (const uint8_t *)registers, 
363                      sizeof(registers[0]) * nb_regs);
364             put_packet(buf);
365             break;
366         case 'G':
367             env = cpu_gdbstub_get_env(opaque);
368             registers = (void *)mem_buf;
369 #if defined(TARGET_I386)
370             hextomem((uint8_t *)registers, p, 16 * 4);
371             for(i = 0; i < 8; i++) {
372                 env->regs[i] = tswapl(registers[i]);
373             }
374             env->eip = registers[8];
375             env->eflags = registers[9];
376 #define LOAD_SEG(index, sreg)\
377             if (tswapl(registers[index]) != env->segs[sreg].selector)\
378                 cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
379             LOAD_SEG(10, R_CS);
380             LOAD_SEG(11, R_SS);
381             LOAD_SEG(12, R_DS);
382             LOAD_SEG(13, R_ES);
383             LOAD_SEG(14, R_FS);
384             LOAD_SEG(15, R_GS);
385 #endif
386             put_packet("OK");
387             break;
388         case 'm':
389             addr = strtoul(p, (char **)&p, 16);
390             if (*p == ',')
391                 p++;
392             len = strtoul(p, NULL, 16);
393             if (memory_rw(mem_buf, addr, len, 0) != 0)
394                 memset(mem_buf, 0, len);
395             memtohex(buf, mem_buf, len);
396             put_packet(buf);
397             break;
398         case 'M':
399             addr = strtoul(p, (char **)&p, 16);
400             if (*p == ',')
401                 p++;
402             len = strtoul(p, (char **)&p, 16);
403             if (*p == ',')
404                 p++;
405             hextomem(mem_buf, p, len);
406             if (memory_rw(mem_buf, addr, len, 1) != 0)
407                 put_packet("ENN");
408             else
409                 put_packet("OK");
410             break;
411         case 'Z':
412             type = strtoul(p, (char **)&p, 16);
413             if (*p == ',')
414                 p++;
415             addr = strtoul(p, (char **)&p, 16);
416             if (*p == ',')
417                 p++;
418             len = strtoul(p, (char **)&p, 16);
419             if (type == 0 || type == 1) {
420                 env = cpu_gdbstub_get_env(opaque);
421                 if (cpu_breakpoint_insert(env, addr) < 0)
422                     goto breakpoint_error;
423                 put_packet("OK");
424             } else {
425             breakpoint_error:
426                 put_packet("ENN");
427             }
428             break;
429         case 'z':
430             type = strtoul(p, (char **)&p, 16);
431             if (*p == ',')
432                 p++;
433             addr = strtoul(p, (char **)&p, 16);
434             if (*p == ',')
435                 p++;
436             len = strtoul(p, (char **)&p, 16);
437             if (type == 0 || type == 1) {
438                 env = cpu_gdbstub_get_env(opaque);
439                 cpu_breakpoint_remove(env, addr);
440                 put_packet("OK");
441             } else {
442                 goto breakpoint_error;
443             }
444             break;
445         default:
446             /* put empty packet */
447             buf[0] = '\0';
448             put_packet(buf);
449             break;
450         }
451     }
452     return 0;
453 }