X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fremote.c;h=efdc7d94a07a1fe1a9d12a000c28ce5ea3191704;hb=a94abe5bb7a71b207691f8b50406166eefda8186;hp=821524392ade8d955ae13464c644b305ec59a80b;hpb=5594d534a24ff0e48806803376209d4b27ec8351;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/remote.c b/gdb/remote.c index 821524392a..efdc7d94a0 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1,23 +1,42 @@ -/* Memory-access and commands for inferior process, for GDB. - Copyright (C) 1988-1991 Free Software Foundation, Inc. +/* Remote target communications for serial-line targets in custom GDB protocol + Copyright 1988, 1991, 1992, 1993 Free Software Foundation, Inc. This file is part of GDB. -GDB is free software; you can redistribute it and/or modify +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. -GDB is distributed in the hope that it will be useful, +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with GDB; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Remote communication protocol. + + A debug packet whose contents are + is encapsulated for transmission in the form: + + $ # CSUM1 CSUM2 + + must be ASCII alphanumeric and cannot include characters + '$' or '#' + + CSUM1 and CSUM2 are ascii hex representation of an 8-bit + checksum of , the most significant nibble is sent first. + the hex digits 0-9,a-f are used. + + Receiver responds with: + + + - if CSUM is correct and ready for next packet + - - if CSUM is incorrect + + is as follows: All values are encoded in ascii hex digits. Request Packet @@ -37,6 +56,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ read mem mAA..AA,LLLL AA..AA is address, LLLL is length. reply XX..XX XX..XX is mem contents + Can be fewer bytes than requested + if able to read only part of the data. or ENN NN is errno write mem MAA..AA,LLLL:XX..XX @@ -44,7 +65,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ LLLL is number of bytes, XX..XX is data reply OK for success - ENN for an error + ENN for an error (this includes the case + where only part of the data was + written). cont cAA..AA AA..AA is address to resume If AA..AA is omitted, @@ -63,99 +86,203 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ The reply comes when the machine stops. It is SAA AA is the "signal number" - kill req k + or... TAAn...:r...;n:r...;n...:r...; + AA = signal number + n... = register number + r... = register contents + or... WAA The process extited, and AA is + the exit status. This is only + applicable for certains sorts of + targets. + or... NAATT;DD;BB Relocate the object file. + AA = signal number + TT = text address + DD = data address + BB = bss address + This is used by the NLM stub, + which is why it only has three + addresses rather than one per + section: the NLM stub always + sees only three sections, even + though gdb may see more. + + kill request k + + toggle debug d toggle debug flag (see 386 & 68k stubs) + reset r reset -- see sparc stub. + reserved On other requests, the stub should + ignore the request and send an empty + response ($#). This way + we can extend the protocol and GDB + can tell whether the stub it is + talking to uses the old or the new. */ -#include +#include "defs.h" #include #include -#include "defs.h" -#include "param.h" #include "frame.h" #include "inferior.h" +#include "bfd.h" +#include "symfile.h" #include "target.h" #include "wait.h" #include "terminal.h" +#include "gdbcmd.h" +#include "objfiles.h" +#include "gdb-stabs.h" + +#include "dcache.h" +#include "remote-utils.h" +#if !defined(DONT_USE_REMOTE) #ifdef USG #include #endif #include +#include "serial.h" + +/* Prototypes for local functions */ + +static int +remote_write_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len)); + +static int +remote_read_bytes PARAMS ((CORE_ADDR memaddr, unsigned char *myaddr, int len)); + +static void +remote_files_info PARAMS ((struct target_ops *ignore)); + +static int +remote_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len, + int should_write, struct target_ops *target)); + +static void +remote_prepare_to_store PARAMS ((void)); + +static void +remote_fetch_registers PARAMS ((int regno)); + +static void +remote_resume PARAMS ((int pid, int step, int siggnal)); + +static int +remote_start_remote PARAMS ((char *dummy)); + +static void +remote_open PARAMS ((char *name, int from_tty)); + +static void +remote_close PARAMS ((int quitting)); + +static void +remote_store_registers PARAMS ((int regno)); + +static void +getpkt PARAMS ((char *buf, int forever)); + +static void +putpkt PARAMS ((char *buf)); + +static void +remote_send PARAMS ((char *buf)); + +static int +readchar PARAMS ((void)); + +static int +remote_wait PARAMS ((WAITTYPE *status)); + +static int +tohex PARAMS ((int nib)); + +static int +fromhex PARAMS ((int a)); + +static void +remote_detach PARAMS ((char *args, int from_tty)); -extern void add_syms_addr_command (); -extern struct value *call_function_by_hand(); -extern void start_remote (); +static void +remote_interrupt PARAMS ((int signo)); + +static void +remote_interrupt_twice PARAMS ((int signo)); extern struct target_ops remote_ops; /* Forward decl */ -static int kiodebug; -static int timeout = 5; +/* This was 5 seconds, which is a long time to sit and wait. + Unless this is going though some terminal server or multiplexer or + other form of hairy serial connection, I would think 2 seconds would + be plenty. */ +static int timeout = 2; #if 0 int icache; #endif -/* Descriptor for I/O to remote machine. Initialize it to -1 so that +/* FIXME: This is a hack which lets this file compile. It should be getting + this setting from remote-utils.c. */ +#define remote_debug (0) + +/* Descriptor for I/O to remote machine. Initialize it to NULL so that remote_open knows that we don't have a file open when the program starts. */ -int remote_desc = -1; +serial_t remote_desc = NULL; -#define PBUFSIZ 400 +#define PBUFSIZ 1024 /* Maximum number of bytes to read/write at once. The value here is chosen to fill up a packet (the headers account for the 32). */ #define MAXBUFBYTES ((PBUFSIZ-32)/2) -static void remote_send (); -static void putpkt (); -static void getpkt (); -#if 0 -static void dcache_flush (); +/* Round up PBUFSIZ to hold all the registers, at least. */ +#if REGISTER_BYTES > MAXBUFBYTES +#undef PBUFSIZ +#define PBUFSIZ (REGISTER_BYTES * 2 + 32) #endif - -/* Called when SIGALRM signal sent due to alarm() timeout. */ -#ifndef HAVE_TERMIO -void -remote_timer () -{ - if (kiodebug) - printf ("remote_timer called\n"); +/* Clean up connection to a remote debugger. */ - alarm (timeout); +/* ARGSUSED */ +static void +remote_close (quitting) + int quitting; +{ + if (remote_desc) + SERIAL_CLOSE (remote_desc); + remote_desc = NULL; } -#endif -/* Initialize remote connection */ +/* Stub for catch_errors. */ -void -remote_start() +static int +remote_start_remote (dummy) + char *dummy; { -} + immediate_quit = 1; /* Allow user to interrupt it */ -/* Clean up connection to a remote debugger. */ + /* Ack any packet which the remote side has already sent. */ + /* I'm not sure this \r is needed; we don't use it any other time we + send an ack. */ + SERIAL_WRITE (remote_desc, "+\r", 2); + putpkt ("?"); /* initiate a query from remote machine */ + immediate_quit = 0; -/* ARGSUSED */ -void -remote_close (quitting) - int quitting; -{ - if (remote_desc >= 0) - close (remote_desc); - remote_desc = -1; + start_remote (); /* Initialize gdb process mechanisms */ + return 1; } /* Open a connection to a remote debugger. NAME is the filename used for communication. */ -void +static DCACHE *remote_dcache; + +static void remote_open (name, from_tty) char *name; int from_tty; { - TERMINAL sg; - if (name == 0) error ( "To open a remote debug connection, you need to specify what serial\n\ @@ -163,47 +290,36 @@ device is attached to the remote system (e.g. /dev/ttya)."); target_preopen (from_tty); - remote_close (0); + unpush_target (&remote_ops); -#if 0 - dcache_init (); -#endif + remote_dcache = dcache_init (remote_read_bytes, remote_write_bytes); - remote_desc = open (name, O_RDWR); - if (remote_desc < 0) + remote_desc = SERIAL_OPEN (name); + if (!remote_desc) perror_with_name (name); - ioctl (remote_desc, TIOCGETP, &sg); -#ifdef HAVE_TERMIO - sg.c_cc[VMIN] = 0; /* read with timeout. */ - sg.c_cc[VTIME] = timeout * 10; - sg.c_lflag &= ~(ICANON | ECHO); -#else - sg.sg_flags = RAW; -#endif - ioctl (remote_desc, TIOCSETP, &sg); + if (SERIAL_SETBAUDRATE (remote_desc, sr_get_baud_rate())) + { + SERIAL_CLOSE (remote_desc); + perror_with_name (name); + } + + SERIAL_RAW (remote_desc); if (from_tty) - printf ("Remote debugging using %s\n", name); + { + puts_filtered ("Remote debugging using "); + puts_filtered (name); + puts_filtered ("\n"); + } push_target (&remote_ops); /* Switch to using remote target now */ -#ifndef HAVE_TERMIO -#ifndef NO_SIGINTERRUPT - /* Cause SIGALRM's to make reads fail. */ - if (siginterrupt (SIGALRM, 1) != 0) - perror ("remote_open: error in siginterrupt"); -#endif - - /* Set up read timeout timer. */ - if ((void (*)()) signal (SIGALRM, remote_timer) == (void (*)()) -1) - perror ("remote_open: error in signal"); -#endif - - /* Ack any packet which the remote side has already sent. */ - write (remote_desc, "+", 1); - putpkt ("?"); /* initiate a query from remote machine */ - - start_remote (); /* Initialize gdb process mechanisms */ + /* Start the remote connection; if error (0), discard this target. + In particular, if the user quits, be sure to discard it + (we'd be in an inconsistent state otherwise). */ + if (!catch_errors (remote_start_remote, (char *)0, + "Couldn't establish connection to remote target\n", RETURN_MASK_ALL)) + pop_target(); } /* remote_detach() @@ -224,7 +340,7 @@ remote_detach (args, from_tty) pop_target (); if (from_tty) - printf ("Ending remote debugging.\n"); + puts_filtered ("Ending remote debugging.\n"); } /* Convert hex digit A to a number. */ @@ -256,50 +372,216 @@ tohex (nib) /* Tell the remote machine to resume. */ -void -remote_resume (step, siggnal) - int step, siggnal; +static void +remote_resume (pid, step, siggnal) + int pid, step, siggnal; { char buf[PBUFSIZ]; if (siggnal) - error ("Can't send signals to a remote system."); + { + char *name; + target_terminal_ours_for_output (); + printf_filtered ("Can't send signals to a remote system. "); + name = strsigno (siggnal); + if (name) + printf_filtered (name); + else + printf_filtered ("Signal %d", siggnal); + printf_filtered (" not sent.\n"); + target_terminal_inferior (); + } -#if 0 - dcache_flush (); -#endif + dcache_flush (remote_dcache); strcpy (buf, step ? "s": "c"); putpkt (buf); } + +/* Send ^C to target to halt it. Target will respond, and send us a + packet. */ + +static void +remote_interrupt (signo) + int signo; +{ + /* If this doesn't work, try more severe steps. */ + signal (signo, remote_interrupt_twice); + + if (remote_debug) + printf ("remote_interrupt called\n"); + + SERIAL_WRITE (remote_desc, "\003", 1); /* Send a ^C */ +} + +static void (*ofunc)(); + +/* The user typed ^C twice. */ +static void +remote_interrupt_twice (signo) + int signo; +{ + signal (signo, ofunc); + + target_terminal_ours (); + if (query ("Interrupted while waiting for the program.\n\ +Give up (and stop debugging it)? ")) + { + target_mourn_inferior (); + return_to_top_level (RETURN_QUIT); + } + else + { + signal (signo, remote_interrupt); + target_terminal_inferior (); + } +} /* Wait until the remote machine stops, then return, storing status in STATUS just as `wait' would. Returns "pid" (though it's not clear what, if anything, that means in the case of this target). */ -int +static int remote_wait (status) WAITTYPE *status; { unsigned char buf[PBUFSIZ]; WSETEXIT ((*status), 0); - getpkt (buf); - if (buf[0] == 'E') - error ("Remote failure reply: %s", buf); - if (buf[0] != 'S') - error ("Invalid remote reply: %s", buf); + + while (1) + { + unsigned char *p; + + ofunc = (void (*)()) signal (SIGINT, remote_interrupt); + getpkt ((char *) buf, 1); + signal (SIGINT, ofunc); + + if (buf[0] == 'E') + warning ("Remote failure reply: %s", buf); + else if (buf[0] == 'T') + { + int i; + long regno; + char regs[MAX_REGISTER_RAW_SIZE]; + + /* Expedited reply, containing Signal, {regno, reg} repeat */ + /* format is: 'Tssn...:r...;n...:r...;n...:r...;#cc', where + ss = signal number + n... = register number + r... = register contents + */ + + p = &buf[3]; /* after Txx */ + + while (*p) + { + unsigned char *p1; + + regno = strtol (p, &p1, 16); /* Read the register number */ + + if (p1 == p) + warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n", + p1, buf); + + p = p1; + + if (*p++ != ':') + warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n", + p, buf); + + if (regno >= NUM_REGS) + warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n", + regno, p, buf); + + for (i = 0; i < REGISTER_RAW_SIZE (regno); i++) + { + if (p[0] == 0 || p[1] == 0) + warning ("Remote reply is too short: %s", buf); + regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); + p += 2; + } + + if (*p++ != ';') + warning ("Remote register badly formatted: %s", buf); + + supply_register (regno, regs); + } + break; + } + else if (buf[0] == 'N') + { + unsigned char *p1; + bfd_vma text_addr, data_addr, bss_addr; + + /* Relocate object file. Format is NAATT;DD;BB where AA is + the signal number, TT is the new text address, DD is the + new data address, and BB is the new bss address. This is + used by the NLM stub; gdb may see more sections. */ + p = &buf[3]; + text_addr = strtol (p, &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + data_addr = strtol (p, &p1, 16); + if (p1 == p || *p1 != ';') + warning ("Malformed relocation packet: Packet '%s'", buf); + p = p1 + 1; + bss_addr = strtol (p, &p1, 16); + if (p1 == p) + warning ("Malformed relocation packet: Packet '%s'", buf); + + if (symfile_objfile != NULL) + { + struct section_offsets *offs; + + /* FIXME: Why don't the various symfile_offsets routines + in the sym_fns vectors set this? */ + if (symfile_objfile->num_sections == 0) + symfile_objfile->num_sections = SECT_OFF_MAX; + + offs = ((struct section_offsets *) + alloca (sizeof (struct section_offsets) + + (symfile_objfile->num_sections + * sizeof (offs->offsets)))); + memcpy (offs, symfile_objfile->section_offsets, + (sizeof (struct section_offsets) + + (symfile_objfile->num_sections + * sizeof (offs->offsets)))); + ANOFFSET (offs, SECT_OFF_TEXT) = text_addr; + ANOFFSET (offs, SECT_OFF_DATA) = data_addr; + ANOFFSET (offs, SECT_OFF_BSS) = bss_addr; + + objfile_relocate (symfile_objfile, offs); + } + break; + } + else if (buf[0] == 'W') + { + /* The remote process exited. */ + WSETEXIT (*status, (fromhex (buf[1]) << 4) + fromhex (buf[2])); + return 0; + } + else if (buf[0] == 'S') + break; + else + warning ("Invalid remote reply: %s", buf); + } + WSETSTOP ((*status), (((fromhex (buf[1])) << 4) + (fromhex (buf[2])))); + return 0; } -/* Read the remote registers into the block REGS. */ +/* Number of bytes of registers this stub implements. */ +static int register_bytes_found; +/* Read the remote registers into the block REGS. */ /* Currently we just read all the registers, so we don't use regno. */ /* ARGSUSED */ -void +static void remote_fetch_registers (regno) int regno; { @@ -311,6 +593,9 @@ remote_fetch_registers (regno) sprintf (buf, "g"); remote_send (buf); + /* Unimplemented registers read as all bits zero. */ + memset (regs, 0, REGISTER_BYTES); + /* Reply describes registers byte by byte, each byte encoded as two hex characters. Suck them all up, then supply them to the register cacheing/storage mechanism. */ @@ -318,11 +603,29 @@ remote_fetch_registers (regno) p = buf; for (i = 0; i < REGISTER_BYTES; i++) { - if (p[0] == 0 || p[1] == 0) - error ("Remote reply is too short: %s", buf); + if (p[0] == 0) + break; + if (p[1] == 0) + { + warning ("Remote reply is of odd length: %s", buf); + /* Don't change register_bytes_found in this case, and don't + print a second warning. */ + goto supply_them; + } regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]); p += 2; } + + if (i != register_bytes_found) + { + register_bytes_found = i; +#ifdef REGISTER_BYTES_OK + if (!REGISTER_BYTES_OK (i)) + warning ("Remote reply is too short: %s", buf); +#endif + } + + supply_them: for (i = 0; i < NUM_REGS; i++) supply_register (i, ®s[REGISTER_BYTE(i)]); } @@ -330,17 +633,18 @@ remote_fetch_registers (regno) /* Prepare to store registers. Since we send them all, we have to read out the ones we don't want to change first. */ -void +static void remote_prepare_to_store () { - remote_fetch_registers (-1); + /* Make sure the entire registers array is valid. */ + read_register_bytes (0, (char *)NULL, REGISTER_BYTES); } /* Store the remote registers from the contents of the block REGISTERS. FIXME, eventually just store one register if that's all that is needed. */ /* ARGSUSED */ -int +static void remote_store_registers (regno) int regno; { @@ -354,7 +658,8 @@ remote_store_registers (regno) each byte encoded as two hex characters. */ p = buf + 1; - for (i = 0; i < REGISTER_BYTES; i++) + /* remote_prepare_to_store insures that register_bytes_found gets set. */ + for (i = 0; i < register_bytes_found; i++) { *p++ = tohex ((registers[i] >> 4) & 0xf); *p++ = tohex (registers[i] & 0xf); @@ -362,17 +667,27 @@ remote_store_registers (regno) *p = '\0'; remote_send (buf); - return 0; } #if 0 + +/* Use of the data cache is disabled because it loses for looking at + and changing hardware I/O ports and the like. Accepting `volatile' + would perhaps be one way to fix it, but a better way which would + win for more cases would be to use the executable file for the text + segment, like the `icache' code below but done cleanly (in some + target-independent place, perhaps in target_xfer_memory, perhaps + based on assigning each target a speed or perhaps by some simpler + mechanism). */ + /* Read a word from remote address ADDR and return it. This goes through the data cache. */ -int +static int remote_fetch_word (addr) CORE_ADDR addr; { +#if 0 if (icache) { extern CORE_ADDR text_start, text_end; @@ -384,18 +699,19 @@ remote_fetch_word (addr) return buffer; } } - return dcache_fetch (addr); +#endif + return dcache_fetch (remote_dcache, addr); } /* Write a word WORD into remote address ADDR. This goes through the data cache. */ -void +static void remote_store_word (addr, word) CORE_ADDR addr; int word; { - dcache_poke (addr, word); + dcache_poke (remote_dcache, addr, word); } #endif /* 0 */ @@ -403,12 +719,14 @@ remote_store_word (addr, word) This does not inform the data cache; the data cache uses this. MEMADDR is the address in the remote memory space. MYADDR is the address of the buffer in our space. - LEN is the number of bytes. */ + LEN is the number of bytes. -void + Returns number of bytes transferred, or 0 for error. */ + +static int remote_write_bytes (memaddr, myaddr, len) CORE_ADDR memaddr; - char *myaddr; + unsigned char *myaddr; int len; { char buf[PBUFSIZ]; @@ -420,7 +738,7 @@ remote_write_bytes (memaddr, myaddr, len) sprintf (buf, "M%x,%x:", memaddr, len); - /* Command describes registers byte by byte, + /* We send target system values byte by byte, in increasing byte addresses, each byte encoded as two hex characters. */ p = buf + strlen (buf); @@ -431,19 +749,33 @@ remote_write_bytes (memaddr, myaddr, len) } *p = '\0'; - remote_send (buf); + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + return len; } /* Read memory data directly from the remote machine. This does not use the data cache; the data cache uses this. MEMADDR is the address in the remote memory space. MYADDR is the address of the buffer in our space. - LEN is the number of bytes. */ + LEN is the number of bytes. -void + Returns number of bytes transferred, or 0 for error. */ + +static int remote_read_bytes (memaddr, myaddr, len) CORE_ADDR memaddr; - char *myaddr; + unsigned char *myaddr; int len; { char buf[PBUFSIZ]; @@ -454,34 +786,52 @@ remote_read_bytes (memaddr, myaddr, len) abort (); sprintf (buf, "m%x,%x", memaddr, len); - remote_send (buf); + putpkt (buf); + getpkt (buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } - /* Reply describes registers byte by byte, + /* Reply describes memory byte by byte, each byte encoded as two hex characters. */ p = buf; for (i = 0; i < len; i++) { if (p[0] == 0 || p[1] == 0) - error ("Remote reply is too short: %s", buf); + /* Reply is short. This means that we were able to read only part + of what we wanted to. */ + break; myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]); p += 2; } + return i; } /* Read or write LEN bytes from inferior memory at MEMADDR, transferring to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is nonzero. Returns length of data written or read; 0 for error. */ -int -remote_xfer_inferior_memory(memaddr, myaddr, len, should_write) +/* ARGSUSED */ +static int +remote_xfer_memory(memaddr, myaddr, len, should_write, target) CORE_ADDR memaddr; char *myaddr; int len; int should_write; + struct target_ops *target; /* ignored */ { - int origlen = len; int xfersize; + int bytes_xferred; + int total_xferred = 0; + while (len > 0) { if (len > MAXBUFBYTES) @@ -490,59 +840,45 @@ remote_xfer_inferior_memory(memaddr, myaddr, len, should_write) xfersize = len; if (should_write) - remote_write_bytes(memaddr, myaddr, xfersize); + bytes_xferred = remote_write_bytes (memaddr, myaddr, xfersize); else - remote_read_bytes (memaddr, myaddr, xfersize); - memaddr += xfersize; - myaddr += xfersize; - len -= xfersize; + bytes_xferred = remote_read_bytes (memaddr, myaddr, xfersize); + + /* If we get an error, we are done xferring. */ + if (bytes_xferred == 0) + break; + + memaddr += bytes_xferred; + myaddr += bytes_xferred; + len -= bytes_xferred; + total_xferred += bytes_xferred; } - return origlen; /* no error possible */ + return total_xferred; } -void -remote_files_info () +static void +remote_files_info (ignore) + struct target_ops *ignore; { - printf ("remote files info missing here. FIXME.\n"); + puts_filtered ("Debugging a target over a serial line.\n"); } -/* +/* Stuff for dealing with the packets which are part of this protocol. + See comment at top of file for details. */ -A debug packet whose contents are -is encapsulated for transmission in the form: - - $ # CSUM1 CSUM2 - - must be ASCII alphanumeric and cannot include characters - '$' or '#' - - CSUM1 and CSUM2 are ascii hex representation of an 8-bit - checksum of , the most significant nibble is sent first. - the hex digits 0-9,a-f are used. - -Receiver responds with: - - + - if CSUM is correct and ready for next packet - - - if CSUM is incorrect - -*/ +/* Read a single character from the remote end, masking it down to 7 bits. */ static int readchar () { - char buf; - - buf = '\0'; -#ifdef HAVE_TERMIO - /* termio does the timeout for us. */ - read (remote_desc, &buf, 1); -#else - alarm (timeout); - read (remote_desc, &buf, 1); - alarm (0); -#endif + int ch; + + ch = SERIAL_READCHAR (remote_desc, timeout); - return buf & 0x7f; + if (ch < 0) + return ch; + + return ch & 0x7f; } /* Send the command in BUF to the remote machine, @@ -555,7 +891,7 @@ remote_send (buf) { putpkt (buf); - getpkt (buf); + getpkt (buf, 0); if (buf[0] == 'E') error ("Remote failure reply: %s", buf); @@ -570,14 +906,17 @@ putpkt (buf) { int i; unsigned char csum = 0; - char buf2[500]; + char buf2[PBUFSIZ]; int cnt = strlen (buf); - char ch; + int ch; char *p; /* Copy the packet into buffer BUF2, encapsulating it and giving it a checksum. */ + if (cnt > sizeof(buf2) - 5) /* Prosanity check */ + abort(); + p = buf2; *p++ = '$'; @@ -592,61 +931,113 @@ putpkt (buf) /* Send it over and over until we get a positive ack. */ - do { - if (kiodebug) - { - *p = '\0'; - printf ("Sending packet: %s (%s)\n", buf2, buf); - } - write (remote_desc, buf2, p - buf2); - - /* read until either a timeout occurs (\0) or '+' is read */ - do { - ch = readchar (); - } while ((ch != '+') && (ch != '\0')); - } while (ch != '+'); + while (1) + { + if (remote_debug) + { + *p = '\0'; + printf ("Sending packet: %s...", buf2); fflush(stdout); + } + if (SERIAL_WRITE (remote_desc, buf2, p - buf2)) + perror_with_name ("putpkt: write failed"); + + /* read until either a timeout occurs (-2) or '+' is read */ + while (1) + { + ch = readchar (); + + switch (ch) + { + case '+': + if (remote_debug) + printf("Ack\n"); + return; + case SERIAL_TIMEOUT: + break; /* Retransmit buffer */ + case SERIAL_ERROR: + perror_with_name ("putpkt: couldn't read ACK"); + case SERIAL_EOF: + error ("putpkt: EOF while trying to read ACK"); + default: + if (remote_debug) + printf ("%02X %c ", ch&0xFF, ch); + continue; + } + break; /* Here to retransmit */ + } + } } /* Read a packet from the remote machine, with error checking, - and store it in BUF. */ + and store it in BUF. BUF is expected to be of size PBUFSIZ. + If FOREVER, wait forever rather than timing out; this is used + while the target is executing user code. */ static void -getpkt (buf) +getpkt (buf, forever) char *buf; + int forever; { char *bp; unsigned char csum; - int c; + int c = 0; unsigned char c1, c2; - -#if 0 - /* Sorry, this will cause all hell to break loose, i.e. we'll end - up in the command loop with an inferior, but (at least if this - happens in remote_wait or some such place) without a current_frame, - having set up prev_* in wait_for_inferior, etc. - - If it is necessary to have such an "emergency exit", seems like - the only plausible thing to do is to say the inferior died, and - make the user reattach if they want to. Perhaps with a prompt - asking for confirmation. */ - - /* allow immediate quit while reading from device, it could be hung */ - immediate_quit++; -#endif /* 0 */ + int retries = 0; +#define MAX_RETRIES 10 while (1) { + /* This can loop forever if the remote side sends us characters + continuously, but if it pauses, we'll get a zero from readchar + because of timeout. Then we'll count that as a retry. */ + + c = readchar(); + if (c > 0 && c != '$') + continue; + + if (c == SERIAL_TIMEOUT) + { + if (forever) + continue; + if (++retries >= MAX_RETRIES) + if (remote_debug) puts_filtered ("Timed out.\n"); + goto out; + } + + if (c == SERIAL_EOF) + error ("Remote connection closed"); + if (c == SERIAL_ERROR) + perror_with_name ("Remote communication error"); + /* Force csum to be zero here because of possible error retry. */ csum = 0; - - while ((c = readchar()) != '$'); - bp = buf; + while (1) { c = readchar (); + if (c == SERIAL_TIMEOUT) + { + if (remote_debug) + puts_filtered ("Timeout in mid-packet, retrying\n"); + goto whole; /* Start a new packet, count retries */ + } + if (c == '$') + { + if (remote_debug) + puts_filtered ("Saw new packet start in middle of old one\n"); + goto whole; /* Start a new packet, count retries */ + } if (c == '#') break; + if (bp >= buf+PBUFSIZ-1) + { + *bp = '\0'; + puts_filtered ("Remote packet too long: "); + puts_filtered (buf); + puts_filtered ("\n"); + goto whole; + } *bp++ = c; csum += c; } @@ -656,195 +1047,140 @@ getpkt (buf) c2 = fromhex (readchar ()); if ((csum & 0xff) == (c1 << 4) + c2) break; - printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", - (c1 << 4) + c2, csum & 0xff, buf); - write (remote_desc, "-", 1); + printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=", + (c1 << 4) + c2, csum & 0xff); + puts_filtered (buf); + puts_filtered ("\n"); + + /* Try the whole thing again. */ +whole: + if (++retries < MAX_RETRIES) + { + SERIAL_WRITE (remote_desc, "-", 1); + } + else + { + printf ("Ignoring packet error, continuing...\n"); + break; + } } -#if 0 - immediate_quit--; -#endif +out: - write (remote_desc, "+", 1); + SERIAL_WRITE (remote_desc, "+", 1); - if (kiodebug) - fprintf (stderr,"Packet received :%s\n", buf); + if (remote_debug) + fprintf (stderr,"Packet received: %s\n", buf); } -/* The data cache leads to incorrect results because it doesn't know about - volatile variables, thus making it impossible to debug functions which - use hardware registers. Therefore it is #if 0'd out. Effect on - performance is some, for backtraces of functions with a few - arguments each. For functions with many arguments, the stack - frames don't fit in the cache blocks, which makes the cache less - helpful. Disabling the cache is a big performance win for fetching - large structures, because the cache code fetched data in 16-byte - chunks. */ -#if 0 -/* The data cache records all the data read from the remote machine - since the last time it stopped. - - Each cache block holds 16 bytes of data - starting at a multiple-of-16 address. */ - -#define DCACHE_SIZE 64 /* Number of cache blocks */ - -struct dcache_block { - struct dcache_block *next, *last; - unsigned int addr; /* Address for which data is recorded. */ - int data[4]; -}; - -struct dcache_block dcache_free, dcache_valid; - -/* Free all the data cache blocks, thus discarding all cached data. */ - static void -dcache_flush () +remote_kill () { - register struct dcache_block *db; - - while ((db = dcache_valid.next) != &dcache_valid) - { - remque (db); - insque (db, &dcache_free); - } + putpkt ("k"); + /* Don't wait for it to die. I'm not really sure it matters whether + we do or not. For the existing stubs, kill is a noop. */ + target_mourn_inferior (); } -/* - * If addr is present in the dcache, return the address of the block - * containing it. - */ - -struct dcache_block * -dcache_hit (addr) -{ - register struct dcache_block *db; - - if (addr & 3) - abort (); - - /* Search all cache blocks for one that is at this address. */ - db = dcache_valid.next; - while (db != &dcache_valid) - { - if ((addr & 0xfffffff0) == db->addr) - return db; - db = db->next; - } - return NULL; -} - -/* Return the int data at address ADDR in dcache block DC. */ - -int -dcache_value (db, addr) - struct dcache_block *db; - unsigned int addr; +static void +remote_mourn () { - if (addr & 3) - abort (); - return (db->data[(addr>>2)&3]); + unpush_target (&remote_ops); + generic_mourn_inferior (); } + +#ifdef REMOTE_BREAKPOINT -/* Get a free cache block, put it on the valid list, - and return its address. The caller should store into the block - the address and data that it describes. */ - -struct dcache_block * -dcache_alloc () -{ - register struct dcache_block *db; - - if ((db = dcache_free.next) == &dcache_free) - /* If we can't get one from the free list, take last valid */ - db = dcache_valid.last; +/* On some machines, e.g. 68k, we may use a different breakpoint instruction + than other targets. */ +static unsigned char break_insn[] = REMOTE_BREAKPOINT; - remque (db); - insque (db, &dcache_valid); - return (db); -} +/* Check that it fits in BREAKPOINT_MAX bytes. */ +static unsigned char check_break_insn_size[BREAKPOINT_MAX] = REMOTE_BREAKPOINT; -/* Return the contents of the word at address ADDR in the remote machine, - using the data cache. */ +#else /* No REMOTE_BREAKPOINT. */ -int -dcache_fetch (addr) - CORE_ADDR addr; -{ - register struct dcache_block *db; +/* Same old breakpoint instruction. This code does nothing different + than mem-break.c. */ +static unsigned char break_insn[] = BREAKPOINT; - db = dcache_hit (addr); - if (db == 0) - { - db = dcache_alloc (); - remote_read_bytes (addr & ~0xf, db->data, 16); - db->addr = addr & ~0xf; - } - return (dcache_value (db, addr)); -} +#endif /* No REMOTE_BREAKPOINT. */ -/* Write the word at ADDR both in the data cache and in the remote machine. */ +/* Insert a breakpoint on targets that don't have any better breakpoint + support. We read the contents of the target location and stash it, + then overwrite it with a breakpoint instruction. ADDR is the target + location in the target machine. CONTENTS_CACHE is a pointer to + memory allocated for saving the target contents. It is guaranteed + by the caller to be long enough to save sizeof BREAKPOINT bytes (this + is accomplished via BREAKPOINT_MAX). */ -dcache_poke (addr, data) +static int +remote_insert_breakpoint (addr, contents_cache) CORE_ADDR addr; - int data; + char *contents_cache; { - register struct dcache_block *db; + int val; - /* First make sure the word is IN the cache. DB is its cache block. */ - db = dcache_hit (addr); - if (db == 0) - { - db = dcache_alloc (); - remote_read_bytes (addr & ~0xf, db->data, 16); - db->addr = addr & ~0xf; - } + val = target_read_memory (addr, contents_cache, sizeof break_insn); - /* Modify the word in the cache. */ - db->data[(addr>>2)&3] = data; + if (val == 0) + val = target_write_memory (addr, (char *)break_insn, sizeof break_insn); - /* Send the changed word. */ - remote_write_bytes (addr, &data, 4); + return val; } -/* Initialize the data cache. */ - -dcache_init () +static int +remote_remove_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; { - register i; - register struct dcache_block *db; - - db = (struct dcache_block *) xmalloc (sizeof (struct dcache_block) * - DCACHE_SIZE); - dcache_free.next = dcache_free.last = &dcache_free; - dcache_valid.next = dcache_valid.last = &dcache_valid; - for (i=0;i