cannot simply write segment registers in system mode
[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 #if defined(CONFIG_USER_ONLY)
372 #define LOAD_SEG(index, sreg)\
373             if (tswapl(registers[index]) != env->segs[sreg].selector)\
374                 cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
375             LOAD_SEG(10, R_CS);
376             LOAD_SEG(11, R_SS);
377             LOAD_SEG(12, R_DS);
378             LOAD_SEG(13, R_ES);
379             LOAD_SEG(14, R_FS);
380             LOAD_SEG(15, R_GS);
381 #endif
382 #endif
383             put_packet("OK");
384             break;
385         case 'm':
386             addr = strtoul(p, (char **)&p, 16);
387             if (*p == ',')
388                 p++;
389             len = strtoul(p, NULL, 16);
390             if (memory_rw(mem_buf, addr, len, 0) != 0)
391                 memset(mem_buf, 0, len);
392             memtohex(buf, mem_buf, len);
393             put_packet(buf);
394             break;
395         case 'M':
396             addr = strtoul(p, (char **)&p, 16);
397             if (*p == ',')
398                 p++;
399             len = strtoul(p, (char **)&p, 16);
400             if (*p == ',')
401                 p++;
402             hextomem(mem_buf, p, len);
403             if (memory_rw(mem_buf, addr, len, 1) != 0)
404                 put_packet("ENN");
405             else
406                 put_packet("OK");
407             break;
408         case 'Z':
409             type = strtoul(p, (char **)&p, 16);
410             if (*p == ',')
411                 p++;
412             addr = strtoul(p, (char **)&p, 16);
413             if (*p == ',')
414                 p++;
415             len = strtoul(p, (char **)&p, 16);
416             if (type == 0 || type == 1) {
417                 env = cpu_gdbstub_get_env(opaque);
418                 if (cpu_breakpoint_insert(env, addr) < 0)
419                     goto breakpoint_error;
420                 put_packet("OK");
421             } else {
422             breakpoint_error:
423                 put_packet("ENN");
424             }
425             break;
426         case 'z':
427             type = strtoul(p, (char **)&p, 16);
428             if (*p == ',')
429                 p++;
430             addr = strtoul(p, (char **)&p, 16);
431             if (*p == ',')
432                 p++;
433             len = strtoul(p, (char **)&p, 16);
434             if (type == 0 || type == 1) {
435                 env = cpu_gdbstub_get_env(opaque);
436                 cpu_breakpoint_remove(env, addr);
437                 put_packet("OK");
438             } else {
439                 goto breakpoint_error;
440             }
441             break;
442         case 'Q':
443             if (!strncmp(p, "Tinit", 5)) {
444                 /* init traces */
445                 put_packet("OK");
446             } else if (!strncmp(p, "TStart", 6)) {
447                 /* start log (gdb 'tstart' command) */
448                 cpu_set_log(CPU_LOG_ALL);
449                 put_packet("OK");
450             } else if (!strncmp(p, "TStop", 5)) {
451                 /* stop log (gdb 'tstop' command) */
452                 cpu_set_log(0);
453                 put_packet("OK");
454             } else {
455                 goto unknown_command;
456             }
457             break;
458         default:
459         unknown_command:
460             /* put empty packet */
461             buf[0] = '\0';
462             put_packet(buf);
463             break;
464         }
465     }
466     return 0;
467 }