Commit | Line | Data |
---|---|---|
cc61838f WJ |
1 | /*- |
2 | * Copyright (c) 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Van Jacobson and Steven McCanne of Lawrence Berkeley Laboratory. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. All advertising materials mentioning features or use of this software | |
17 | * must display the following acknowledgement: | |
18 | * This product includes software developed by the University of | |
19 | * California, Berkeley and its contributors. | |
20 | * 4. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
36 | * $Header: remote.c,v 1.24 91/03/22 15:35:15 mccanne Exp $; | |
37 | */ | |
38 | ||
39 | #ifndef lint | |
40 | static char sccsid[] = "@(#)remote.c 6.5 (Berkeley) 5/8/91"; | |
41 | #endif /* not lint */ | |
42 | ||
43 | #include "param.h" | |
44 | ||
45 | #include <stdio.h> | |
46 | #include <varargs.h> | |
47 | ||
48 | #include <signal.h> | |
49 | #include <sys/types.h> | |
50 | #include <sys/ioctl.h> | |
51 | #include <sys/file.h> | |
52 | ||
53 | #include "defs.h" | |
54 | #include "frame.h" | |
55 | #include "inferior.h" | |
56 | #include "wait.h" | |
57 | ||
58 | #include "kgdb_proto.h" | |
59 | ||
60 | static FILE *kiodebug; | |
61 | static int icache = 1; | |
62 | extern int kernel_debugging; | |
63 | ||
64 | static int remote_cache_valid; | |
65 | static int remote_instub; | |
66 | ||
67 | static void remote_signal(); | |
68 | static void remote_debug(); | |
69 | static void print_msg(); | |
70 | ||
71 | static int remote_mtu; | |
72 | static int (*send_msg)(); | |
73 | static int (*recv_msg)(); | |
74 | static void (*closelink)(); | |
75 | ||
76 | static u_char *inbuffer; | |
77 | static u_char *outbuffer; | |
78 | ||
79 | /* | |
80 | * Statistics. | |
81 | */ | |
82 | static int remote_ierrs; | |
83 | static int remote_oerrs; | |
84 | static int remote_seqerrs; | |
85 | static int remote_spurious; | |
86 | ||
87 | #define PUTCMD(cmd) m_xchg(cmd, (u_char *)0, 0, (u_char *)0, (int *)0) | |
88 | ||
89 | /* | |
90 | * Send an outbound message to the remote machine and read the reply. | |
91 | * Either or both message buffers may be NULL. | |
92 | */ | |
93 | static int | |
94 | m_xchg(type, out, outlen, in, inlen) | |
95 | int type; | |
96 | u_char *out; | |
97 | int outlen; | |
98 | u_char *in; | |
99 | int *inlen; | |
100 | { | |
101 | register int err, (*send)() = send_msg, (*recv)() = recv_msg; | |
102 | int ack; | |
103 | static int seqbit = 0; | |
104 | ||
105 | if (!remote_instub) { | |
106 | remote_instub = 1; | |
107 | PUTCMD(KGDB_EXEC); | |
108 | } | |
109 | ||
110 | seqbit ^= KGDB_SEQ; | |
111 | while (1) { | |
112 | err = (*send)(type | seqbit, out, outlen); | |
113 | if (err) { | |
114 | ++remote_oerrs; | |
115 | if (kiodebug) | |
116 | remote_debug("send error %d\n", err); | |
117 | } | |
118 | if (kiodebug) | |
119 | print_msg(type | seqbit, out, outlen, 'O'); | |
120 | ||
121 | recv: | |
122 | err = (*recv)(&ack, in, inlen); | |
123 | if (err) { | |
124 | ++remote_ierrs; | |
125 | if (kiodebug) | |
126 | remote_debug("recv error %d\n", err); | |
127 | remote_cache_valid = 0; | |
128 | } else if (kiodebug) | |
129 | print_msg(ack, in, inlen ? *inlen : 0, 'I'); | |
130 | ||
131 | if (err) | |
132 | continue; | |
133 | ||
134 | if ((ack & KGDB_ACK) == 0 || KGDB_CMD(ack) != KGDB_CMD(type)) { | |
135 | ++remote_spurious; | |
136 | continue; | |
137 | } | |
138 | if ((ack & KGDB_SEQ) ^ seqbit) { | |
139 | ++remote_seqerrs; | |
140 | goto recv; | |
141 | } | |
142 | return ack; | |
143 | } | |
144 | } | |
145 | ||
146 | /* | |
147 | * Wait for the specified message type. Discard anything else. | |
148 | * (this is used by 'remote-signal' to help us resync with other side.) | |
149 | */ | |
150 | static void | |
151 | m_recv(type, in, inlen) | |
152 | int type; | |
153 | u_char *in; | |
154 | int *inlen; | |
155 | { | |
156 | int reply, err; | |
157 | ||
158 | while (1) { | |
159 | err = (*recv_msg)(&reply, in, inlen); | |
160 | if (err) { | |
161 | ++remote_ierrs; | |
162 | if (kiodebug) | |
163 | remote_debug("recv error %d\n", err); | |
164 | } else if (kiodebug) | |
165 | print_msg(reply, in, inlen ? *inlen : 0, 'I'); | |
166 | ||
167 | if (KGDB_CMD(reply) == type) | |
168 | return; | |
169 | ++remote_spurious; | |
170 | } | |
171 | } | |
172 | ||
173 | /* | |
174 | * Send a message. Do not wait for *any* response from the other side. | |
175 | * Some other thread of control will pick up the ack that will be generated. | |
176 | */ | |
177 | static void | |
178 | m_send(type, buf, len) | |
179 | int type; | |
180 | u_char *buf; | |
181 | int len; | |
182 | { | |
183 | int err; | |
184 | ||
185 | if (!remote_instub) { | |
186 | remote_instub = 1; | |
187 | PUTCMD(KGDB_EXEC); | |
188 | } | |
189 | ||
190 | err = (*send_msg)(type, buf, len); | |
191 | if (err) { | |
192 | ++remote_ierrs; | |
193 | if (kiodebug) | |
194 | remote_debug("[send error %d] ", err); | |
195 | } | |
196 | if (kiodebug) | |
197 | print_msg(type, buf, len, 'O'); | |
198 | } | |
199 | ||
200 | /* | |
201 | * Open a connection to a remote debugger. | |
202 | * NAME is the filename used for communication. | |
203 | */ | |
204 | void | |
205 | remote_open(name, from_tty) | |
206 | char *name; | |
207 | int from_tty; | |
208 | { | |
209 | int bufsize; | |
210 | ||
211 | remote_debugging = 0; | |
212 | if (sl_open(name, &send_msg, &recv_msg, &closelink, &remote_mtu, | |
213 | &bufsize)) | |
214 | return; | |
215 | if (from_tty) | |
216 | printf("Remote debugging using %s\n", name); | |
217 | remote_debugging = 1; | |
218 | ||
219 | remote_cache_valid = 0; | |
220 | ||
221 | inbuffer = (u_char *)malloc(bufsize); | |
222 | outbuffer = (u_char *)malloc(bufsize); | |
223 | ||
224 | remote_signal(); | |
225 | ||
226 | remote_ierrs = 0; | |
227 | remote_oerrs = 0; | |
228 | remote_spurious = 0; | |
229 | } | |
230 | ||
231 | /* | |
232 | * Close the open connection to the remote debugger. Use this when you want | |
233 | * to detach and do something else with your gdb. | |
234 | */ | |
235 | void | |
236 | remote_close(from_tty) | |
237 | int from_tty; | |
238 | { | |
239 | if (!remote_debugging) | |
240 | error("remote debugging not enabled"); | |
241 | ||
242 | remote_debugging = 0; | |
243 | /* | |
244 | * Take remote machine out of debug mode. | |
245 | */ | |
246 | (void)PUTCMD(KGDB_KILL); | |
247 | (*closelink)(); | |
248 | if (from_tty) | |
249 | printf("Ending remote debugging\n"); | |
250 | ||
251 | free((char *)inbuffer); | |
252 | free((char *)outbuffer); | |
253 | } | |
254 | ||
255 | /* | |
256 | * Tell the remote machine to resume. | |
257 | */ | |
258 | int | |
259 | remote_resume(step, signal) | |
260 | int step, signal; | |
261 | { | |
262 | if (!step) { | |
263 | (void)PUTCMD(KGDB_CONT); | |
264 | remote_instub = 0; | |
265 | } else { | |
266 | #ifdef NO_SINGLE_STEP | |
267 | single_step(0); | |
268 | #else | |
269 | (void)PUTCMD(KGDB_STEP); | |
270 | #endif | |
271 | } | |
272 | } | |
273 | ||
274 | /* | |
275 | * Wait until the remote machine stops, then return, storing status in STATUS | |
276 | * just as `wait' would. | |
277 | */ | |
278 | int | |
279 | remote_wait(status) | |
280 | WAITTYPE *status; | |
281 | { | |
282 | int len; | |
283 | ||
284 | WSETEXIT((*status), 0); | |
285 | /* | |
286 | * When the machine stops, it will send us a KGDB_SIGNAL message, | |
287 | * so we wait for one of these. | |
288 | */ | |
289 | m_recv(KGDB_SIGNAL, inbuffer, &len); | |
290 | WSETSTOP((*status), inbuffer[0]); | |
291 | } | |
292 | ||
293 | /* | |
294 | * Register context as of last remote_fetch_registers(). | |
295 | */ | |
296 | static char reg_cache[REGISTER_BYTES]; | |
297 | ||
298 | /* | |
299 | * Read the remote registers into the block REGS. | |
300 | */ | |
301 | void | |
302 | remote_fetch_registers(regs) | |
303 | char *regs; | |
304 | { | |
305 | int regno, len, rlen, ack; | |
306 | u_char *cp, *ep; | |
307 | ||
308 | regno = -1; | |
309 | do { | |
310 | outbuffer[0] = regno + 1; | |
311 | ack = m_xchg(remote_cache_valid ? | |
312 | KGDB_REG_R|KGDB_DELTA : KGDB_REG_R, | |
313 | outbuffer, 1, inbuffer, &len); | |
314 | cp = inbuffer; | |
315 | ep = cp + len; | |
316 | while (cp < ep) { | |
317 | regno = *cp++; | |
318 | rlen = REGISTER_RAW_SIZE(regno); | |
319 | bcopy((char *)cp, | |
320 | ®_cache[REGISTER_BYTE(regno)], rlen); | |
321 | cp += rlen; | |
322 | } | |
323 | } while (ack & KGDB_MORE); | |
324 | ||
325 | remote_cache_valid = 1; | |
326 | bcopy(reg_cache, regs, REGISTER_BYTES); | |
327 | } | |
328 | ||
329 | /* | |
330 | * Store the remote registers from the contents of the block REGS. | |
331 | */ | |
332 | void | |
333 | remote_store_registers(regs) | |
334 | char *regs; | |
335 | { | |
336 | u_char *cp, *ep; | |
337 | int regno, off, rlen; | |
338 | ||
339 | cp = outbuffer; | |
340 | ep = cp + remote_mtu; | |
341 | ||
342 | for (regno = 0; regno < NUM_REGS; ++regno) { | |
343 | off = REGISTER_BYTE(regno); | |
344 | rlen = REGISTER_RAW_SIZE(regno); | |
345 | if (!remote_cache_valid || | |
346 | bcmp(®s[off], ®_cache[off], rlen) != 0) { | |
347 | if (cp + rlen + 1 >= ep) { | |
348 | (void)m_xchg(KGDB_REG_W, | |
349 | outbuffer, cp - outbuffer, | |
350 | (u_char *)0, (int *)0); | |
351 | cp = outbuffer; | |
352 | } | |
353 | *cp++ = regno; | |
354 | bcopy(®s[off], cp, rlen); | |
355 | cp += rlen; | |
356 | } | |
357 | } | |
358 | if (cp != outbuffer) | |
359 | (void)m_xchg(KGDB_REG_W, outbuffer, cp - outbuffer, | |
360 | (u_char *)0, (int *)0); | |
361 | bcopy(regs, reg_cache, REGISTER_BYTES); | |
362 | } | |
363 | ||
364 | /* | |
365 | * Store a chunk of memory into the remote host. | |
366 | * 'remote_addr' is the address in the remote memory space. | |
367 | * 'cp' is the address of the buffer in our space, and 'len' is | |
368 | * the number of bytes. Returns an errno status. | |
369 | */ | |
370 | int | |
371 | remote_write_inferior_memory(remote_addr, cp, len) | |
372 | CORE_ADDR remote_addr; | |
373 | u_char *cp; | |
374 | int len; | |
375 | { | |
376 | int cnt; | |
377 | ||
378 | while (len > 0) { | |
379 | cnt = min(len, remote_mtu - 4); | |
380 | bcopy((char *)&remote_addr, outbuffer, 4); | |
381 | bcopy(cp, outbuffer + 4, cnt); | |
382 | (void)m_xchg(KGDB_MEM_W, outbuffer, cnt + 4, inbuffer, &len); | |
383 | ||
384 | if (inbuffer[0]) | |
385 | return inbuffer[0]; | |
386 | ||
387 | remote_addr += cnt; | |
388 | cp += cnt; | |
389 | len -= cnt; | |
390 | } | |
391 | return 0; | |
392 | } | |
393 | ||
394 | /* | |
395 | * Read memory data directly from the remote machine. | |
396 | * 'remote_addr' is the address in the remote memory space. | |
397 | * 'cp' is the address of the buffer in our space, and 'len' is | |
398 | * the number of bytes. Returns an errno status. | |
399 | */ | |
400 | static int | |
401 | remote_read_memory(remote_addr, cp, len) | |
402 | CORE_ADDR remote_addr; | |
403 | u_char *cp; | |
404 | int len; | |
405 | { | |
406 | int cnt, inlen; | |
407 | ||
408 | while (len > 0) { | |
409 | cnt = min(len, remote_mtu - 1); | |
410 | outbuffer[0] = cnt; | |
411 | bcopy((char *)&remote_addr, (char *)&outbuffer[1], 4); | |
412 | ||
413 | (void)m_xchg(KGDB_MEM_R, outbuffer, 5, inbuffer, &inlen); | |
414 | ||
415 | if (inbuffer[0] != 0) | |
416 | return inbuffer[0]; | |
417 | ||
418 | if (cnt != inlen - 1) | |
419 | /* XXX */ | |
420 | error("remote_read_memory() request botched"); | |
421 | ||
422 | bcopy((char *)&inbuffer[1], (char *)cp, cnt); | |
423 | ||
424 | remote_addr += cnt; | |
425 | cp += cnt; | |
426 | len -= cnt; | |
427 | } | |
428 | return 0; | |
429 | } | |
430 | ||
431 | int | |
432 | remote_read_inferior_memory(remote_addr, cp, len) | |
433 | CORE_ADDR remote_addr; | |
434 | char *cp; | |
435 | int len; | |
436 | { | |
437 | int stat = 0; | |
438 | ||
439 | if (icache) { | |
440 | extern CORE_ADDR text_start, text_end; | |
441 | CORE_ADDR xferend = remote_addr + len; | |
442 | ||
443 | if (remote_addr < text_end && text_start < xferend) { | |
444 | /* | |
445 | * at least part of this xfer is in the text | |
446 | * space -- xfer the overlap from the exec file. | |
447 | */ | |
448 | if (remote_addr >= text_start && xferend < text_end) | |
449 | return (xfer_core_file(remote_addr, cp, len)); | |
450 | if (remote_addr >= text_start) { | |
451 | int i = text_end - remote_addr; | |
452 | ||
453 | if (stat = xfer_core_file(remote_addr, cp, i)) | |
454 | return (stat); | |
455 | remote_addr += i; | |
456 | cp += i; | |
457 | len -= i; | |
458 | } else if (xferend <= text_end) { | |
459 | int i = xferend - text_start; | |
460 | ||
461 | len = text_start - remote_addr; | |
462 | if (stat = xfer_core_file(text_start, | |
463 | cp + len, i)) | |
464 | return (stat); | |
465 | } | |
466 | } | |
467 | } | |
468 | return remote_read_memory(remote_addr, cp, len); | |
469 | } | |
470 | ||
471 | /* | |
472 | * Signal the remote machine. The remote end might be idle or it might | |
473 | * already be in debug mode -- we need to handle both case. Thus, we use | |
474 | * the framing character as the wakeup byte, and send a SIGNAL packet. | |
475 | * If the remote host is idle, the framing character will wake it up. | |
476 | * If it is in the kgdb stub, then we will get a SIGNAL reply. | |
477 | */ | |
478 | static void | |
479 | remote_signal() | |
480 | { | |
481 | if (!remote_debugging) | |
482 | printf("Remote debugging not enabled.\n"); | |
483 | else { | |
484 | remote_instub = 0; | |
485 | m_send(KGDB_SIGNAL, (u_char *)0, 0); | |
486 | } | |
487 | } | |
488 | ||
489 | static void | |
490 | remote_signal_command() | |
491 | { | |
492 | extern int stop_after_attach; | |
493 | ||
494 | if (!remote_debugging) | |
495 | error("Not debugging remote."); | |
496 | remote_cache_valid = 0; | |
497 | remote_signal(); | |
498 | restart_remote(); | |
499 | } | |
500 | ||
501 | /* | |
502 | * Print a message for debugging. | |
503 | */ | |
504 | static void | |
505 | print_msg(type, buf, len, dir) | |
506 | int type; | |
507 | u_char *buf; | |
508 | int len; | |
509 | int dir; | |
510 | { | |
511 | int i; | |
512 | char *s; | |
513 | ||
514 | switch (KGDB_CMD(type)) { | |
515 | case KGDB_MEM_R: s = "memr"; break; | |
516 | case KGDB_MEM_W: s = "memw"; break; | |
517 | case KGDB_REG_R: s = "regr"; break; | |
518 | case KGDB_REG_W: s = "regw"; break; | |
519 | case KGDB_CONT: s = "cont"; break; | |
520 | case KGDB_STEP: s = "step"; break; | |
521 | case KGDB_KILL: s = "kill"; break; | |
522 | case KGDB_SIGNAL: s = "sig "; break; | |
523 | case KGDB_EXEC: s = "exec"; break; | |
524 | default: s = "unk "; break; | |
525 | } | |
526 | remote_debug("%c %c%c%c%c %s (%02x): ", dir, | |
527 | (type & KGDB_ACK) ? 'A' : '.', | |
528 | (type & KGDB_DELTA) ? 'D' : '.', | |
529 | (type & KGDB_MORE) ? 'M' : '.', | |
530 | (type & KGDB_SEQ) ? '-' : '+', | |
531 | s, type); | |
532 | if (buf) | |
533 | for (i = 0; i < len; ++i) | |
534 | remote_debug("%02x", buf[i]); | |
535 | remote_debug("\n"); | |
536 | } | |
537 | ||
538 | static void | |
539 | set_remote_text_refs_command(arg, from_tty) | |
540 | char *arg; | |
541 | int from_tty; | |
542 | { | |
543 | icache = !parse_binary_operation("set remote-text-refs", arg); | |
544 | } | |
545 | ||
546 | static void | |
547 | remote_debug_command(arg, from_tty) | |
548 | char *arg; | |
549 | int from_tty; | |
550 | { | |
551 | char *name; | |
552 | ||
553 | if (kiodebug != 0 && kiodebug != stderr) | |
554 | (void)fclose(kiodebug); | |
555 | ||
556 | if (arg == 0) { | |
557 | kiodebug = 0; | |
558 | printf("Remote debugging off.\n"); | |
559 | return; | |
560 | } | |
561 | if (arg[0] == '-') { | |
562 | kiodebug = stderr; | |
563 | name = "stderr"; | |
564 | } else { | |
565 | kiodebug = fopen(arg, "w"); | |
566 | if (kiodebug == 0) { | |
567 | printf("Cannot open '%s'.\n", arg); | |
568 | return; | |
569 | } | |
570 | name = arg; | |
571 | } | |
572 | printf("Remote debugging output routed to %s.\n", name); | |
573 | } | |
574 | ||
575 | /* ARGSUSED */ | |
576 | static void | |
577 | remote_info(arg, from_tty) | |
578 | char *arg; | |
579 | int from_tty; | |
580 | { | |
581 | printf("Using %s for text references.\n", | |
582 | icache? "local executable" : "remote"); | |
583 | printf("Protocol debugging is %s.\n", kiodebug? "on" : "off"); | |
584 | printf("%d spurious input messages.\n", remote_spurious); | |
585 | printf("%d input errors; %d output errors; %d sequence errors.\n", | |
586 | remote_ierrs, remote_oerrs, remote_seqerrs); | |
587 | } | |
588 | ||
589 | /* VARARGS */ | |
590 | static void | |
591 | remote_debug(va_alist) | |
592 | va_dcl | |
593 | { | |
594 | register char *cp; | |
595 | va_list ap; | |
596 | ||
597 | va_start(ap); | |
598 | cp = va_arg(ap, char *); | |
599 | (void)vfprintf(kiodebug, cp, ap); | |
600 | va_end(ap); | |
601 | fflush(kiodebug); | |
602 | } | |
603 | ||
604 | extern struct cmd_list_element *setlist; | |
605 | ||
606 | void | |
607 | _initialize_remote() | |
608 | { | |
609 | add_com("remote-signal", class_run, remote_signal_command, | |
610 | "If remote debugging, send interrupt signal to remote."); | |
611 | add_cmd("remote-text-refs", class_support, | |
612 | set_remote_text_refs_command, | |
613 | "Enable/disable use of local executable for text segment references.\n\ | |
614 | If on, all memory read/writes go to remote.\n\ | |
615 | If off, text segment reads use the local executable.", | |
616 | &setlist); | |
617 | ||
618 | add_com("remote-debug", class_run, remote_debug_command, | |
619 | "With a file name argument, enables output of remote protocol debugging\n\ | |
620 | messages to said file. If file is `-', stderr is used.\n\ | |
621 | With no argument, remote debugging is disabled."); | |
622 | ||
623 | add_info("remote", remote_info, | |
624 | "Show current settings of remote debugging options."); | |
625 | } | |
626 |