/[gxemul]/trunk/src/debugger/debugger_gdb.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/debugger/debugger_gdb.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (hide annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 9586 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


1 dpavlin 24 /*
2     * Copyright (C) 2006 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 26 * $Id: debugger_gdb.c,v 1.12 2006/06/24 19:52:28 debug Exp $
29 dpavlin 24 *
30     * Routines used for communicating with the GNU debugger, using the GDB
31     * remote serial protocol.
32     */
33    
34     #include <stdio.h>
35     #include <stdlib.h>
36     #include <string.h>
37     #include <sys/types.h>
38     #include <sys/socket.h>
39     #include <netinet/in.h>
40     #include <fcntl.h>
41     #include <unistd.h>
42    
43     #include "cpu.h"
44 dpavlin 26 #include "debugger.h"
45 dpavlin 24 #include "debugger_gdb.h"
46     #include "machine.h"
47     #include "memory.h"
48    
49    
50     extern int single_step;
51     extern int exit_debugger;
52    
53    
54     /*
55     * debugger_gdb_listen():
56     *
57     * Set up a GDB remote listening port for a specific emulated machine.
58     */
59     static void debugger_gdb_listen(struct machine *machine)
60     {
61     int listen_socket, res;
62     struct sockaddr_in si;
63     struct sockaddr_in incoming;
64     socklen_t incoming_len;
65    
66     printf("----------------------------------------------------------"
67     "---------------------\nWaiting for incoming remote GDB connection"
68     " on port %i...\n", machine->gdb.port);
69    
70     listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
71     if (listen_socket < 0) {
72     perror("socket");
73     exit(1);
74     }
75    
76     memset((char *)&si, sizeof(si), 0);
77     si.sin_family = AF_INET;
78     si.sin_port = htons(machine->gdb.port);
79     si.sin_addr.s_addr = htonl(INADDR_ANY);
80     if (bind(listen_socket, (struct sockaddr *)&si, sizeof(si)) < 0) {
81     perror("bind");
82     exit(1);
83     }
84    
85     if (listen(listen_socket, 1) != 0) {
86     perror("listen");
87     }
88    
89     machine->gdb.socket = accept(listen_socket,
90     (struct sockaddr *)&incoming, &incoming_len);
91     printf("Connected; GDB socket = %i\n", machine->gdb.socket);
92    
93     /* Set the socket to non-blocking: */
94     res = fcntl(machine->gdb.socket, F_GETFL);
95     fcntl(machine->gdb.socket, F_SETFL, res | O_NONBLOCK);
96     }
97    
98    
99     /*
100     * send_packet():
101     *
102     * Sends a packet with the correct checksum.
103     */
104     static void send_packet(struct machine *machine, char *msg)
105     {
106     unsigned char hex[17] = "0123456789abcdef";
107     unsigned char checksum = 0x00;
108     int i = 0;
109     unsigned char ch;
110    
111     while (msg[i]) {
112     checksum += (unsigned char) msg[i];
113     i ++;
114     }
115    
116     ch = '$'; write(machine->gdb.socket, &ch, 1);
117     write(machine->gdb.socket, msg, i);
118     ch = '#'; write(machine->gdb.socket, &ch, 1);
119     ch = hex[checksum >> 4]; write(machine->gdb.socket, &ch, 1);
120     ch = hex[checksum & 15]; write(machine->gdb.socket, &ch, 1);
121     }
122    
123    
124     /*
125     * debugger_gdb__execute_command():
126     *
127     * Execute the command in the machine's receive buffer.
128     */
129     void debugger_gdb__execute_command(struct machine *machine)
130     {
131     char *cmd = (char *) machine->gdb.rx_buf;
132    
133     fatal("[ Remote GDB command: '%s' ]\n", machine->gdb.rx_buf);
134    
135     if (strcmp(cmd, "?") == 0) {
136     send_packet(machine, "S00");
137     } else if (strcmp(cmd, "g") == 0 || strncmp(cmd, "p", 1) == 0) {
138     char *reply = cpu_gdb_stub(machine->cpus[0], cmd);
139     if (reply != NULL) {
140     send_packet(machine, reply);
141     free(reply);
142     }
143     } else if (strcmp(cmd, "c") == 0) {
144     send_packet(machine, "OK");
145     exit_debugger = 1;
146     } else if (strncmp(cmd, "Hc", 2) == 0) {
147     fatal("[ TODO: GDB SET THREAD ]\n");
148     send_packet(machine, "OK");
149     } else if (strncmp(cmd, "m", 1) == 0) {
150     /* Memory read */
151     char *p = strchr(cmd, ',');
152     if (p == NULL) {
153     send_packet(machine, "E00");
154     } else {
155     uint64_t addr = strtoull(cmd + 1, NULL, 16);
156     uint64_t len = strtoull(p + 1, NULL, 16);
157     char *reply = malloc(len * 2 + 1);
158     size_t i;
159    
160     reply[0] = '\0';
161     for (i=0; i<len; i++) {
162     unsigned char ch;
163     machine->cpus[0]->memory_rw(machine->cpus[0],
164     machine->cpus[0]->mem, addr+i, &ch,
165     sizeof(ch), MEM_READ, CACHE_NONE
166     | NO_EXCEPTIONS);
167     snprintf(reply + strlen(reply),
168     len*2, "%02x", ch);
169     }
170    
171     send_packet(machine, reply);
172     free(reply);
173     }
174     } else if (strcmp(cmd, "s") == 0) {
175     unsigned char ch = '+';
176     write(machine->gdb.socket, &ch, 1);
177     exit_debugger = -1;
178     } else {
179     fatal("[ (UNKNOWN COMMAND) ]\n");
180     send_packet(machine, "");
181     }
182     }
183    
184    
185     /*
186     * debugger_gdb__check_incoming_char():
187     *
188     * Handle each incoming character.
189     */
190     int debugger_gdb__check_incoming_char(struct machine *machine)
191     {
192     /* int old_state = machine->gdb.rx_state; */
193     unsigned char ch, ch1;
194     ssize_t len = read(machine->gdb.socket, &ch, 1);
195    
196     if (len == 0) {
197     perror("GDB socket read");
198     fprintf(stderr, "Connection closed. Exiting.\n");
199     exit(1);
200     }
201    
202     /* EAGAIN, and similar: */
203     if (len < 0)
204     return 0;
205    
206     /* debug("[ debugger_gdb: received char ");
207     if (ch >= ' ')
208     debug("'%c' ]\n", ch);
209     else
210     debug("0x%02x ]\n", ch); */
211    
212     switch (machine->gdb.rx_state) {
213    
214     case RXSTATE_WAITING_FOR_DOLLAR:
215     if (ch == '$') {
216     machine->gdb.rx_state = RXSTATE_WAITING_FOR_HASH;
217     if (machine->gdb.rx_buf != NULL)
218     free(machine->gdb.rx_buf);
219     machine->gdb.rx_buf_size = 200;
220     machine->gdb.rx_buf = malloc(
221     machine->gdb.rx_buf_size + 1);
222     machine->gdb.rx_buf_curlen = 0;
223     machine->gdb.rx_buf_checksum = 0x00;
224     } else if (ch == 0x03) {
225     fatal("[ GDB break ]\n");
226 dpavlin 26 single_step = ENTER_SINGLE_STEPPING;
227 dpavlin 24 ch = '+';
228     write(machine->gdb.socket, &ch, 1);
229     send_packet(machine, "S02");
230     machine->gdb.rx_state = RXSTATE_WAITING_FOR_DOLLAR;
231     } else {
232     if (ch != '+')
233     debug("[ debugger_gdb: ignoring char '"
234     "%c' ]\n", ch);
235     }
236     break;
237    
238     case RXSTATE_WAITING_FOR_HASH:
239     if (ch == '#') {
240     machine->gdb.rx_state = RXSTATE_WAITING_FOR_CHECKSUM1;
241    
242     machine->gdb.rx_buf[machine->gdb.rx_buf_curlen] = '\0';
243     } else {
244     if (machine->gdb.rx_buf_curlen >=
245     machine->gdb.rx_buf_size) {
246     machine->gdb.rx_buf_size *= 2;
247     machine->gdb.rx_buf = realloc(
248     machine->gdb.rx_buf,
249     machine->gdb.rx_buf_size + 1);
250     }
251    
252     machine->gdb.rx_buf[
253     machine->gdb.rx_buf_curlen ++] = ch;
254    
255     machine->gdb.rx_buf_checksum += ch;
256    
257     /* debug("[ debugger_gdb: current checksum = "
258     "0x%02x ]\n", machine->gdb.rx_buf_checksum); */
259     }
260     break;
261    
262     case RXSTATE_WAITING_FOR_CHECKSUM1:
263     machine->gdb.rx_checksum1 = ch;
264     machine->gdb.rx_state = RXSTATE_WAITING_FOR_CHECKSUM2;
265     break;
266    
267     case RXSTATE_WAITING_FOR_CHECKSUM2:
268     ch1 = machine->gdb.rx_checksum1;
269    
270     if (ch1 >= '0' && ch1 <= '9')
271     ch1 = ch1 - '0';
272     else if (ch1 >= 'a' && ch1 <= 'f')
273     ch1 = 10 + ch1 - 'a';
274     else if (ch1 >= 'A' && ch1 <= 'F')
275     ch1 = 10 + ch1 - 'A';
276    
277     if (ch >= '0' && ch <= '9')
278     ch = ch - '0';
279     else if (ch >= 'a' && ch <= 'f')
280     ch = 10 + ch - 'a';
281     else if (ch >= 'A' && ch <= 'F')
282     ch = 10 + ch - 'A';
283    
284     if (machine->gdb.rx_buf_checksum != ch1 * 16 + ch) {
285     /* Checksum mismatch! */
286    
287     fatal("[ debugger_gdb: CHECKSUM MISMATCH! (0x%02x, "
288     " calculated is 0x%02x ]\n", ch1 * 16 + ch,
289     machine->gdb.rx_buf_checksum);
290    
291     /* Send a NACK message: */
292     ch = '-';
293     write(machine->gdb.socket, &ch, 1);
294     } else {
295     /* Checksum is ok. Send an ACK message... */
296     ch = '+';
297     write(machine->gdb.socket, &ch, 1);
298    
299     /* ... and execute the command: */
300     debugger_gdb__execute_command(machine);
301     }
302    
303     machine->gdb.rx_state = RXSTATE_WAITING_FOR_DOLLAR;
304     break;
305    
306     default:fatal("debugger_gdb_check_incoming(): internal error "
307     "(state %i unknown)\n", machine->gdb.rx_state);
308     exit(1);
309     }
310    
311     /* if (machine->gdb.rx_state != old_state)
312     debug("[ debugger_gdb: state %i -> %i ]\n",
313     old_state, machine->gdb.rx_state); */
314    
315     return 1;
316     }
317    
318    
319     /*
320     * debugger_gdb_check_incoming():
321     *
322     * This function should be called regularly, to check for incoming data on
323     * the remote GDB socket.
324     */
325     void debugger_gdb_check_incoming(struct machine *machine)
326     {
327     while (debugger_gdb__check_incoming_char(machine))
328     ;
329     }
330    
331    
332     /*
333     * debugger_gdb_after_singlestep():
334     *
335     * Single-step works like this:
336     *
337     * GDB to GXemul: s
338     * GXemul to GDB: +
339     * (GXemul single-steps one instruction)
340     * GXemul to GDB: T00
341     *
342     * This function should be called after the instruction has been executed.
343     */
344     void debugger_gdb_after_singlestep(struct machine *machine)
345     {
346     send_packet(machine, "T00");
347     }
348    
349    
350     /*
351     * debugger_gdb_init():
352     *
353     * Initialize stuff needed for a GDB remote connection.
354     */
355     void debugger_gdb_init(struct machine *machine)
356     {
357     if (machine->gdb.port < 1)
358     return;
359    
360     debugger_gdb_listen(machine);
361     }
362    

  ViewVC Help
Powered by ViewVC 1.1.26