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