/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 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 /*
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 * $Id: debugger_gdb.c,v 1.12 2006/06/24 19:52:28 debug Exp $
29 *
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 #include "debugger.h"
45 #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 single_step = ENTER_SINGLE_STEPPING;
227 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