]>
Commit | Line | Data |
---|---|---|
93584146 SC |
1 | /* Remote debugging interface for EST-300 ICE, for GDB |
2 | Copyright 1994 Free Software Foundation, Inc. | |
3 | Contributed by Cygnus Support. | |
4 | ||
5 | Written by Steve Chamberlain for Cygnus Support. | |
6 | ||
7 | This file is part of GDB. | |
8 | ||
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program; if not, write to the Free Software | |
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
22 | ||
23 | ||
24 | #include "defs.h" | |
25 | #include "command.h" | |
26 | #include "gdbcore.h" | |
27 | #include "target.h" | |
28 | #include "wait.h" | |
29 | #include <varargs.h> | |
30 | #include <signal.h> | |
31 | #include <string.h> | |
32 | #include <sys/types.h> | |
33 | #include "serial.h" | |
34 | #include "remote-utils.h" | |
35 | ||
36 | ||
37 | static void expect_char PARAMS ((int)); | |
38 | ||
39 | ||
40 | static void | |
41 | write_and_expect (x) | |
42 | char *x; | |
43 | { | |
44 | sr_write_cr (x); | |
45 | sr_expect (x); | |
46 | } | |
47 | ||
48 | static void | |
49 | expect_char (want) | |
50 | int want; | |
51 | { | |
52 | int c = sr_readchar (); | |
53 | while (c != want) | |
54 | c = sr_readchar (); | |
55 | } | |
56 | ||
57 | ||
58 | static void | |
59 | expect_prompt () | |
60 | { | |
61 | expect_char ('>'); | |
62 | } | |
63 | ||
64 | static int | |
65 | get_hex_digit (ch) | |
66 | int ch; | |
67 | { | |
68 | if (ch >= '0' && ch <= '9') | |
69 | return ch - '0'; | |
70 | else if (ch >= 'A' && ch <= 'F') | |
71 | return ch - 'A' + 10; | |
72 | else if (ch >= 'a' && ch <= 'f') | |
73 | return ch - 'a' + 10; | |
74 | return -1; | |
75 | } | |
76 | ||
77 | static int | |
78 | get_hex (start) | |
79 | int *start; | |
80 | { | |
81 | int value = get_hex_digit (*start); | |
82 | int try; | |
83 | ||
84 | *start = sr_readchar (); | |
85 | while ((try = get_hex_digit (*start)) >= 0) | |
86 | { | |
87 | value <<= 4; | |
88 | value += try; | |
89 | *start = sr_readchar (); | |
90 | } | |
91 | return value; | |
92 | } | |
93 | ||
94 | /* Tell the remote machine to resume. */ | |
95 | ||
96 | static void | |
97 | est_resume (pid, step, sig) | |
98 | int pid, step, sig; | |
99 | { | |
100 | write_and_expect (step ? ".SI" : ".GO"); | |
101 | } | |
102 | ||
103 | /* A reg dump looks like | |
104 | D0 = 00000000 D1 = 00000000 D2 = 00000000 D3 = 00000000 | |
105 | D4 = 00000000 D5 = 00000000 D6 = 00000000 D7 = 00000000 | |
106 | A0 = 00000000 A1 = 00000000 A2 = 00000000 A3 = 00000000 | |
107 | A4 = 00000000 A5 = 00000000 A6 = 00000000 A7 = 001104FE | |
108 | USP = 00110400 SSP*= 001104FE PC = 00229BBC SR = 2000 | |
109 | VBR = 00110000 SFC = 0005 DFC = 0005 | |
110 | ||
111 | or | |
112 | ||
113 | 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00001234 00000000 001104FE 00110400 001104FE 00229BBC 2000 00110000 0005 0005 | |
114 | */ | |
115 | ||
116 | static int | |
117 | target_to_gdb_rn (rn) | |
118 | int rn; | |
119 | { | |
120 | if (rn < 16) | |
121 | return rn; | |
122 | if (rn == 18) | |
123 | return PC_REGNUM; | |
124 | if (rn == 19) | |
125 | return PS_REGNUM; | |
126 | return -1; | |
127 | } | |
128 | ||
129 | ||
130 | static void est_fetch_register (); | |
131 | static void | |
132 | est_fetch_registers () | |
133 | { | |
134 | int regno; | |
135 | unsigned long val; | |
136 | int c; | |
137 | int target_rn; | |
138 | char buf[4]; | |
139 | write_and_expect (".DR"); | |
140 | buf[0] = 0; | |
141 | buf[1] = 0; | |
142 | buf[2] = 0; | |
143 | buf[3] = 0; | |
144 | for (regno = 0; regno < NUM_REGS; regno++) | |
145 | supply_register (regno, buf); | |
146 | ||
147 | c = sr_readchar (); | |
148 | for (target_rn = 0; target_rn < 23; target_rn++) | |
149 | { | |
150 | unsigned long val; | |
151 | while (!isdigit (c) && !isalpha (c)) | |
152 | c = sr_readchar (); | |
153 | ||
154 | while (isdigit (c) || (c >= 'A' && c <= 'F')) | |
155 | { | |
156 | val <<= 4; | |
157 | if (isdigit (c)) | |
158 | val = val + c - '0'; | |
159 | else | |
160 | val = val + c - 'A' + 10; | |
161 | c = sr_readchar (); | |
162 | } | |
163 | ||
164 | regno = target_to_gdb_rn (target_rn); | |
165 | if (regno >= 0) | |
166 | { | |
167 | buf[0] = val >> 24; | |
168 | buf[1] = val >> 16; | |
169 | buf[2] = val >> 8; | |
170 | buf[3] = val >> 0; | |
171 | supply_register (regno, buf); | |
172 | } | |
173 | } | |
174 | expect_prompt(); | |
175 | } | |
176 | ||
177 | /* Fetch register REGNO, or all registers if REGNO is -1. | |
178 | Returns errno value. */ | |
179 | ||
180 | static | |
181 | void | |
182 | est_fetch_register (regno) | |
183 | int regno; | |
184 | { | |
185 | est_fetch_registers (); | |
186 | } | |
187 | ||
188 | /* Store the remote registers from the contents of the block REGS. */ | |
189 | ||
190 | static void est_store_register (); | |
191 | static void | |
192 | est_store_registers () | |
193 | { | |
194 | int regno; | |
195 | ||
196 | for (regno = 0; regno < 18; regno++) | |
197 | est_store_register (regno); | |
198 | registers_changed (); | |
199 | } | |
200 | ||
201 | /* Store register REGNO, or all if REGNO == 0. | |
202 | Return errno value. */ | |
203 | static void | |
204 | est_store_register (regno) | |
205 | int regno; | |
206 | { | |
207 | char buf[20]; | |
208 | if (regno == -1) | |
209 | { | |
210 | est_store_registers (); | |
211 | return; | |
212 | } | |
213 | ||
214 | if (regno < 8) | |
215 | sprintf (buf, ".SR D%d %x", regno, read_register (regno)); | |
216 | else if (regno < 16) | |
217 | sprintf (buf, ".SR A%d %x", regno - 8, read_register (regno)); | |
218 | else if (regno == PC_REGNUM) | |
219 | sprintf (buf, ".SR PC %x", read_register (regno)); | |
220 | else if (regno == PS_REGNUM) | |
221 | sprintf (buf, ".SR SR %x", read_register (regno)); | |
222 | else | |
223 | return; | |
224 | write_and_expect (buf); | |
225 | expect_prompt (); | |
226 | } | |
227 | ||
228 | /* Get ready to modify the registers array. On machines which store | |
229 | individual registers, this doesn't need to do anything. On machines | |
230 | which store all the registers in one fell swoop, this makes sure | |
231 | that registers contains all the registers from the program being | |
232 | debugged. */ | |
233 | ||
234 | ||
235 | static | |
236 | int | |
237 | stickbyte (where, what) | |
238 | char *where; | |
239 | unsigned int what; | |
240 | { | |
241 | static CONST char digs[] = "0123456789ABCDEF"; | |
242 | where[0] = digs[(what >> 4) & 0xf]; | |
243 | where[1] = digs[(what & 0xf) & 0xf]; | |
244 | return what; | |
245 | } | |
246 | ||
247 | /* Copy LEN bytes of data from debugger memory at MYADDR | |
248 | to inferior's memory at MEMADDR. Returns length moved. */ | |
249 | ||
250 | static int | |
251 | est_write_memory (memaddr, myaddr, len) | |
252 | CORE_ADDR memaddr; | |
253 | unsigned char *myaddr; | |
254 | int len; | |
255 | { | |
256 | int i; | |
257 | #define maxstride 128 | |
258 | int stride; | |
259 | ||
260 | write_and_expect (".DL"); | |
261 | expect_char ('+'); | |
262 | for (i = 0; i < len; i += stride) | |
263 | { | |
264 | char compose[maxstride * 2 + 50]; | |
265 | int address = i + memaddr; | |
266 | int j; | |
267 | int check_sum; | |
268 | int where = 0; | |
269 | int alen; | |
270 | stride = len - i; | |
271 | if (stride > maxstride) | |
272 | stride = maxstride; | |
273 | ||
274 | compose[where++] = 'S'; | |
275 | check_sum = 0; | |
276 | if (address >= 0xffffff) | |
277 | { | |
278 | alen = 4; | |
279 | } | |
280 | else if (address >= 0xffff) | |
281 | { | |
282 | alen = 3; | |
283 | } | |
284 | else | |
285 | alen = 2; | |
286 | compose[where++] = alen - 1 + '0'; /* insert type */ | |
287 | check_sum += stickbyte (compose + where, alen + stride + 1); /* Insert length */ | |
288 | where += 2; | |
289 | while (alen > 0) | |
290 | { | |
291 | alen--; | |
292 | check_sum += stickbyte (compose + where, address >> (8 * (alen))); | |
293 | where += 2; | |
294 | } | |
295 | ||
296 | for (j = 0; j < stride; j++) | |
297 | { | |
298 | check_sum += stickbyte (compose + where, myaddr[i + j]); | |
299 | where += 2; | |
300 | } | |
301 | ||
302 | stickbyte (compose + where, ~check_sum); | |
303 | ||
304 | where += 2; | |
305 | compose[where++] = 0; | |
306 | ||
307 | sr_write_cr (compose); | |
308 | while (sr_readchar () != '+') | |
309 | sr_write_cr (compose); | |
310 | } | |
311 | ||
312 | /* Send the trailer record */ | |
313 | sr_write_cr ("S70500000000FA"); | |
314 | expect_prompt (); | |
315 | return len; | |
316 | } | |
317 | ||
318 | ||
319 | ||
320 | /* | |
321 | ||
322 | The dump memory command generates output which looks like: | |
323 | ||
324 | ||
325 | .dmb 0 100 | |
326 | 4E 56 FF FC 4E 71 42 AE FF FC 72 09 B2 AE FF FC NV..NqB...r..... | |
327 | 6C 02 60 12 2F 2E FF FC 4E B9 00 00 00 2A 58 4F l.`./...N....*XO | |
328 | 52 AE FF FC 60 E4 4E 5E 4E 75 4E 56 00 00 20 2E R...`.N^NuNV.. . | |
329 | 00 08 D1 B9 00 00 00 00 4E 5E 4E 75 06 46 40 54 ........N^Nu.F@T | |
330 | 04 45 44 4C 54 45 40 56 42 F4 04 64 24 45 05 05 [email protected]$E.. | |
331 | 00 6D 04 46 00 45 4C 05 04 46 04 4C 44 CD 00 65 .m.F.EL..F.LD..e | |
332 | 40 45 44 55 45 45 45 46 04 44 44 40 05 4D 00 44 @[email protected] | |
333 | ||
334 | */ | |
335 | ||
336 | static int | |
337 | est_read_memory (memaddr, myaddr, len) | |
338 | CORE_ADDR memaddr; | |
339 | unsigned char *myaddr; | |
340 | int len; | |
341 | { | |
342 | int count; | |
343 | int c; | |
344 | char buf[20]; | |
345 | /* Starting address of this pass. */ | |
346 | ||
347 | if (((memaddr - 1) + len) < memaddr) | |
348 | { | |
349 | errno = EIO; | |
350 | return 0; | |
351 | } | |
352 | ||
353 | sprintf (buf, ".dmb %x %x", memaddr, len); | |
354 | write_and_expect (buf); | |
355 | count = 0; | |
356 | ||
357 | c = sr_readchar (); | |
358 | ||
359 | while (count < len) | |
360 | { | |
361 | while (!isdigit (c) && !isalpha (c)) { | |
362 | if (c == '!') | |
363 | { | |
364 | expect_prompt(); | |
365 | errno =EIO; | |
366 | return 0; | |
367 | ||
368 | } | |
369 | c = sr_readchar (); | |
370 | } | |
371 | myaddr[count++] = get_hex (&c); | |
372 | c = sr_readchar (); | |
373 | if (c == ' ') | |
374 | { | |
375 | c = sr_readchar (); | |
376 | if (c == ' ') | |
377 | while (c != '\r') | |
378 | c = sr_readchar (); | |
379 | } | |
380 | } | |
381 | ||
382 | expect_prompt (); | |
383 | ||
384 | ||
385 | return len; | |
386 | } | |
387 | ||
388 | static int | |
389 | est_xfer_inferior_memory (memaddr, myaddr, len, write, target) | |
390 | CORE_ADDR memaddr; | |
391 | unsigned char *myaddr; | |
392 | int len; | |
393 | int write; | |
394 | struct target_ops *target; /* ignored */ | |
395 | { | |
396 | if (write) | |
397 | { | |
398 | return est_write_memory (memaddr, myaddr, len); | |
399 | } | |
400 | else | |
401 | { | |
402 | return est_read_memory (memaddr, myaddr, len); | |
403 | } | |
404 | } | |
405 | ||
406 | ||
407 | #define MAX_DEBUG_BREAKPOINTS 100 | |
408 | ||
409 | extern int memory_breakpoint_size; | |
410 | static CORE_ADDR breakaddr[MAX_DEBUG_BREAKPOINTS] = | |
411 | {0}; | |
412 | ||
413 | int | |
414 | est_clear_all_breakpoints () | |
415 | { | |
416 | int i; | |
417 | for (i = 0; i < MAX_DEBUG_BREAKPOINTS; i++) | |
418 | { | |
419 | breakaddr[i] = 0; | |
420 | } | |
421 | ||
422 | if (sr_is_open ()) | |
423 | { | |
424 | write_and_expect (".RB"); | |
425 | expect_prompt (); | |
426 | } | |
427 | return 0; | |
428 | } | |
429 | ||
430 | static int | |
431 | est_insert_breakpoint (addr, shadow) | |
432 | CORE_ADDR addr; | |
433 | unsigned char *shadow; | |
434 | { | |
435 | int i; | |
436 | ||
437 | for (i = 0; i <= MAX_DEBUG_BREAKPOINTS; i++) | |
438 | if (breakaddr[i] == 0) | |
439 | { | |
440 | char buf[20]; | |
441 | breakaddr[i] = addr; | |
442 | sprintf (buf, ".SB %x", addr); | |
443 | write_and_expect (buf); | |
444 | expect_prompt (); | |
445 | return 0; | |
446 | } | |
447 | error ("Too many breakpoints ( > %d) for the est\n", MAX_DEBUG_BREAKPOINTS); | |
448 | return 1; | |
449 | } | |
450 | ||
451 | static int | |
452 | est_remove_breakpoint (addr, shadow) | |
453 | CORE_ADDR addr; | |
454 | unsigned char *shadow; | |
455 | { | |
456 | int i; | |
457 | ||
458 | for (i = 0; i < MAX_DEBUG_BREAKPOINTS; i++) | |
459 | if (breakaddr[i] == addr) | |
460 | { | |
461 | char buf[20]; | |
462 | breakaddr[i] = 0; | |
463 | sprintf (buf, ".RB %x", addr); | |
464 | write_and_expect (buf); | |
465 | expect_prompt (); | |
466 | return 0; | |
467 | } | |
468 | ||
469 | error ("Can't find breakpoint associated with 0x%x\n", addr); | |
470 | return 1; | |
471 | } | |
472 | ||
473 | ||
474 | /* Wait until the remote machine stops, then return, | |
475 | storing status in STATUS just as `wait' would. */ | |
476 | ||
477 | static int | |
478 | est_wait (pid, status) | |
479 | int pid; | |
480 | struct target_waitstatus *status; | |
481 | { | |
482 | int c = sr_readchar (); | |
483 | while (c != '!') | |
484 | c = sr_readchar (); | |
485 | /* What sort of stop */ | |
486 | c = sr_readchar (); | |
487 | status->kind = TARGET_WAITKIND_STOPPED; | |
488 | switch (c) | |
489 | { | |
490 | case 'E': | |
491 | status->value.sig = TARGET_SIGNAL_BUS; | |
492 | break; | |
493 | /* Address error */ | |
494 | case 'A': | |
495 | status->value.sig = TARGET_SIGNAL_BUS; | |
496 | break; | |
497 | /* Break */ | |
498 | case 'B': | |
499 | status->value.sig = TARGET_SIGNAL_TRAP; | |
500 | break; | |
501 | } | |
502 | expect_prompt (); | |
503 | return 0; | |
504 | } | |
505 | ||
506 | void | |
507 | est_checkin () | |
508 | { | |
509 | write_and_expect (".in"); | |
510 | gr_expect_prompt (); | |
511 | } | |
512 | ||
513 | extern struct gr_settings est_settings; | |
514 | ||
515 | static void | |
516 | est_open (args, from_tty) | |
517 | char *args; | |
518 | int from_tty; | |
519 | { | |
520 | gr_open (args, from_tty, &est_settings); | |
521 | } | |
522 | ||
523 | /* Define the target subroutine names */ | |
524 | ||
525 | struct target_ops est_ops = | |
526 | { | |
527 | "est", | |
528 | "Remote EST-300 target", | |
529 | "Use a remote EST-300 ICE connected by a serial line,\n\ | |
530 | or a network connection.\n\ | |
531 | Arguments are the name of the device for the serial line,\n\ | |
532 | the speed to connect at in bits per second.\n\ | |
533 | eg\n\ | |
534 | target est /dev/ttya 9600\n\ | |
535 | target est foobar", | |
536 | est_open, | |
537 | gr_close, | |
538 | 0, | |
539 | gr_detach, | |
540 | est_resume, | |
541 | est_wait, | |
542 | est_fetch_register, | |
543 | est_store_register, | |
544 | gr_prepare_to_store, | |
545 | est_xfer_inferior_memory, | |
546 | gr_files_info, | |
547 | est_insert_breakpoint, | |
548 | est_remove_breakpoint, /* Breakpoints */ | |
549 | 0, | |
550 | 0, | |
551 | 0, | |
552 | 0, | |
553 | 0, /* Terminal handling */ | |
554 | gr_kill, | |
555 | gr_load_image, /* load */ | |
556 | 0, /* lookup_symbol */ | |
557 | gr_create_inferior, | |
558 | gr_mourn, | |
559 | 0, /* can_run */ | |
560 | 0, /* notice_signals */ | |
561 | 0, /* to_stop */ | |
562 | process_stratum, | |
563 | 0, /* next */ | |
564 | 1, | |
565 | 1, | |
566 | 1, | |
567 | 1, | |
568 | 1, /* all mem, mem, stack, regs, exec */ | |
569 | 0, | |
570 | 0, /* Section pointers */ | |
571 | OPS_MAGIC, /* Always the last thing */ | |
572 | }; | |
573 | ||
574 | static struct gr_settings est_settings = | |
575 | { | |
576 | NULL, /* dcache */ | |
577 | ">", /* prompt */ | |
578 | &est_ops, /* ops */ | |
579 | est_clear_all_breakpoints, | |
580 | est_read_memory, /* readfunc */ | |
581 | est_write_memory, /* writefunc */ | |
582 | est_checkin, /* checkin */ | |
583 | }; | |
584 | ||
585 | void | |
586 | _initialize_remote_est () | |
587 | { | |
588 | add_target (&est_ops); | |
589 | } |