aboutsummaryrefslogtreecommitdiff
path: root/gdb/remote.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/remote.c')
-rw-r--r--gdb/remote.c607
1 files changed, 607 insertions, 0 deletions
diff --git a/gdb/remote.c b/gdb/remote.c
new file mode 100644
index 0000000..23f27df
--- /dev/null
+++ b/gdb/remote.c
@@ -0,0 +1,607 @@
+/* Memory-access and commands for inferior process, for GDB.
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+GDB is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone
+for the consequences of using it or for whether it serves any
+particular purpose or works at all, unless he says so in writing.
+Refer to the GDB General Public License for full details.
+
+Everyone is granted permission to copy, modify and redistribute GDB,
+but only under the conditions described in the GDB General Public
+License. A copy of this license is supposed to have been given to you
+along with GDB so you can know your rights and responsibilities. It
+should be in a file named COPYING. Among other things, the copyright
+notice and this notice must be preserved on all copies.
+
+In other words, go ahead and share GDB, but don't try to stop
+anyone else from sharing it farther. Help stamp out software hoarding!
+*/
+
+/* Remote communication protocol.
+ All values are encoded in ascii hex digits.
+
+ Request Packet
+
+ read registers g
+ reply XX....X Each byte of register data
+ is described by two hex digits.
+ Registers are in the internal order
+ for GDB, and the bytes in a register
+ are in the same order the machine uses.
+ or ENN for an error.
+
+ write regs GXX..XX Each byte of register data
+ is described by two hex digits.
+ reply OK for success
+ ENN for an error
+
+ read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
+ reply XX..XX XX..XX is mem contents
+ or ENN NN is errno
+
+ write mem MAA..AA,LLLL:XX..XX
+ AA..AA is address,
+ LLLL is number of bytes,
+ XX..XX is data
+ reply OK for success
+ ENN for an error
+
+ cont cAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ step sAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ There is no immediate reply to step or cont.
+ The reply comes when the machine stops.
+ It is SAA AA is the "signal number"
+
+ kill req k
+*/
+
+#include <stdio.h>
+#include <signal.h>
+
+#include "defs.h"
+#include "initialize.h"
+#include "param.h"
+#include "frame.h"
+#include "inferior.h"
+
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <a.out.h>
+#include <sys/file.h>
+#include <sgtty.h>
+
+int kiodebug;
+
+int icache;
+
+/* Descriptor for I/O to remote machine. */
+int remote_desc;
+
+#define PBUFSIZ 300
+
+static void remote_send ();
+static void putpkt ();
+static void getpkt ();
+static void dcache_flush ();
+
+START_FILE
+
+/* Open a connection to a remote debugger.
+ NAME is the filename used for communication. */
+
+void
+remote_open (name, from_tty)
+ char *name;
+ int from_tty;
+{
+ struct sgttyb sg;
+
+ remote_debugging = 0;
+ dcache_init ();
+
+ remote_desc = open (name, O_RDWR);
+ if (remote_desc < 0)
+ perror_with_name (name);
+
+ ioctl (remote_desc, TIOCGETP, &sg);
+ sg.sg_flags = RAW;
+ ioctl (remote_desc, TIOCSETP, &sg);
+
+ if (from_tty)
+ printf ("Remote debugging using %s\n", name);
+ remote_debugging = 1;
+}
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (a)
+ int a;
+{
+ if (a >= '0' && a <= '9')
+ return a - '0';
+ else if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ else
+ error ("Reply contains invalid hex digit");
+}
+
+/* Convert number NIB to a hex digit. */
+
+static int
+tohex (nib)
+ int nib;
+{
+ if (nib < 10)
+ return '0'+nib;
+ else
+ return 'a'+nib-10;
+}
+
+/* Tell the remote machine to resume. */
+
+int
+remote_resume (step, signal)
+ int step, signal;
+{
+ char buf[PBUFSIZ];
+
+ dcache_flush ();
+
+ strcpy (buf, step ? "s": "c");
+
+ putpkt (buf);
+}
+
+/* Wait until the remote machine stops, then return,
+ storing status in STATUS just as `wait' would. */
+
+int
+remote_wait (status)
+ union wait *status;
+{
+ char buf[PBUFSIZ];
+
+ status->w_status = 0;
+ getpkt (buf);
+ if (buf[0] == 'E')
+ error ("Remote failure reply: %s", buf);
+ if (buf[0] != 'S')
+ error ("Invalid remote reply: %s", buf);
+ status->w_stopval = WSTOPPED;
+ status->w_stopsig = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
+}
+
+/* Read the remote registers into the block REGS. */
+
+void
+remote_fetch_registers (regs)
+ char *regs;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ sprintf (buf, "g");
+ remote_send (buf);
+
+ /* Reply describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf;
+ for (i = 0; i < REGISTER_BYTES; i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ error ("Remote reply is too short: %s", buf);
+ regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+}
+
+/* Store the remote registers from the contents of the block REGS. */
+
+void
+remote_store_registers (regs)
+ char *regs;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ buf[0] = 'G';
+
+ /* Command describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf + 1;
+ for (i = 0; i < REGISTER_BYTES; i++)
+ {
+ *p++ = (regs[i] > 4) & 0xf;
+ *p++ = regs[i] & 0xf;
+ }
+
+ remote_send (buf);
+}
+
+/* Read a word from remote address ADDR and return it.
+ This goes through the data cache. */
+
+int
+remote_fetch_word (addr)
+ CORE_ADDR addr;
+{
+ if (icache)
+ {
+ extern CORE_ADDR text_start, text_end;
+
+ if (addr >= text_start && addr < text_end)
+ {
+ int buffer;
+ xfer_core_file (addr, &buffer, sizeof (int));
+ return buffer;
+ }
+ }
+ return dcache_fetch (addr);
+}
+
+/* Write a word WORD into remote address ADDR.
+ This goes through the data cache. */
+
+void
+remote_store_word (addr, word)
+ CORE_ADDR addr;
+ int word;
+{
+ dcache_poke (addr, word);
+}
+
+/* Write memory data directly to the remote machine.
+ 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. */
+
+void
+remote_write_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ if (len > PBUFSIZ / 2 - 20)
+ abort ();
+
+ sprintf (buf, "M%x,%x:", memaddr, len);
+
+ /* Command describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf + strlen (buf);
+ for (i = 0; i < len; i++)
+ {
+ *p++ = (myaddr[i] > 4) & 0xf;
+ *p++ = myaddr[i] & 0xf;
+ }
+
+ remote_send (buf);
+}
+
+/* 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. */
+
+void
+remote_read_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int i;
+ char *p;
+
+ if (len > PBUFSIZ / 2 - 1)
+ abort ();
+
+ sprintf (buf, "m%x,%x", memaddr, len);
+ remote_send (buf);
+
+ /* Reply describes registers byte by byte,
+ each byte encoded as two hex characters. */
+
+ p = buf;
+ for (i = 0; i < REGISTER_BYTES; i++)
+ {
+ if (p[0] == 0 || p[1] == 0)
+ error ("Remote reply is too short: %s", buf);
+ myaddr[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+ p += 2;
+ }
+}
+
+/*
+
+A debug packet whose contents are <data>
+is encapsulated for transmission in the form:
+
+ $ <data> # CSUM1 CSUM2
+
+ <data> must be ASCII alphanumeric and cannot include characters
+ '$' or '#'
+
+ CSUM1 and CSUM2 are ascii hex representation of an 8-bit
+ checksum of <data>, 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
+
+*/
+
+/* Send the command in BUF to the remote machine,
+ and read the reply into BUF.
+ Report an error if we get an error reply. */
+
+static void
+remote_send (buf)
+ char *buf;
+{
+ int i;
+ putpkt (buf);
+ getpkt (buf);
+
+ if (buf[0] == 'E')
+ error ("Remote failure reply: %s", buf);
+}
+
+/* Send a packet to the remote machine, with error checking.
+ The data of the packet is in BUF. */
+
+static void
+putpkt (buf)
+ char *buf;
+{
+ int i;
+ char csum = 0;
+ char buf2[500];
+ char buf3[1];
+ int cnt = strlen (buf);
+ char *p;
+
+ if (kiodebug)
+ fprintf (stderr, "Sending packet: %s\n", buf);
+
+ /* Copy the packet into buffer BUF2, encapsulating it
+ and giving it a checksum. */
+
+ p = buf2;
+ *p++ = '$';
+
+ for (i = 0; i < cnt; i++)
+ {
+ csum += buf[i];
+ *p++ = buf[i];
+ }
+ *p++ = '#';
+ *p++ = tohex ((csum >> 4) & 0xf);
+ *p++ = tohex (csum & 0xf);
+
+ /* Send it over and over until we get a positive ack. */
+
+ do {
+ write (remote_desc, buf2, p - buf2);
+ read (remote_desc, buf3, 1);
+ } while (buf3[0] != '+');
+}
+
+static int
+readchar ()
+{
+ char buf[1];
+ while (read (remote_desc, buf, 1) != 1) ;
+ return buf[0] & 0x7f;
+}
+
+/* Read a packet from the remote machine, with error checking,
+ and store it in BUF. */
+
+static void
+getpkt (buf)
+ char *buf;
+{
+ char *bp;
+ char csum = 0;
+ int c, c1, c2;
+ extern kiodebug;
+
+ while (1)
+ {
+ while ((c = readchar()) != '$');
+
+ bp = buf;
+ while (1)
+ {
+ c = readchar ();
+ if (c == '#')
+ break;
+ *bp++ = c;
+ csum += c;
+ }
+ *bp = 0;
+
+ c1 = fromhex (readchar ());
+ c2 = fromhex (readchar ());
+ if (csum == (c1 << 4) + c2)
+ break;
+ printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
+ (c1 << 4) + c2, csum, buf);
+ write (remote_desc, "-", 1);
+ }
+
+ write (remote_desc, "+", 1);
+
+ if (kiodebug)
+ fprintf (stderr,"Packet received :%s\n", buf);
+}
+
+/* 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 ()
+{
+ register struct dcache_block *db;
+
+ while ((db = dcache_valid.next) != &dcache_valid)
+ {
+ remque (db);
+ insque (db, &dcache_free);
+ }
+}
+
+/*
+ * 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;
+{
+ if (addr & 3)
+ abort ();
+ return (db->data[(addr>>2)&3]);
+}
+
+/* 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;
+
+ remque (db);
+ insque (db, &dcache_valid);
+ return (db);
+}
+
+/* Return the contents of the word at address ADDR in the remote machine,
+ using the data cache. */
+
+int
+dcache_fetch (addr)
+ CORE_ADDR addr;
+{
+ register struct dcache_block *db;
+
+ 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));
+}
+
+/* Write the word at ADDR both in the data cache and in the remote machine. */
+
+dcache_poke (addr, data)
+ CORE_ADDR addr;
+ int data;
+{
+ register struct dcache_block *db;
+
+ /* 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;
+ }
+
+ /* Modify the word in the cache. */
+ db->data[(addr>>2)&3] = data;
+
+ /* Send the changed word. */
+ remote_write_bytes (addr, &data, 4);
+}
+
+/* Initialize the data cache. */
+
+dcache_init ()
+{
+ 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<DCACHE_SIZE;i++,db++)
+ insque (db, &dcache_free);
+}
+
+static initialize ()
+{
+}
+
+END_FILE