summaryrefslogtreecommitdiff
path: root/gnu/usr.bin
diff options
context:
space:
mode:
authorws <ws@NetBSD.org>2000-03-23 20:44:40 +0000
committerws <ws@NetBSD.org>2000-03-23 20:44:40 +0000
commit0bb2093748a706e3290c27dbcd4f5d20fa6ebaa6 (patch)
tree3eed7bea9aad03a5dbd43e649350962a4abe2c5a /gnu/usr.bin
parent7c8b72d5927d38b58563c44b2ab19aee400bc47a (diff)
Add IPKDB support to GDB.
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r--gnu/usr.bin/gdb/Makefile4
-rw-r--r--gnu/usr.bin/gdb/remote-ipkdb.c753
2 files changed, 755 insertions, 2 deletions
diff --git a/gnu/usr.bin/gdb/Makefile b/gnu/usr.bin/gdb/Makefile
index 0f9bff7a58d..35591563cec 100644
--- a/gnu/usr.bin/gdb/Makefile
+++ b/gnu/usr.bin/gdb/Makefile
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.35 1999/11/26 14:39:47 msaitoh Exp $
+# $NetBSD: Makefile,v 1.36 2000/03/23 20:44:40 ws Exp $
# for OBJECT_FMT
.include <bsd.own.mk>
@@ -44,7 +44,7 @@ COMMON_SRCS= version.c blockframe.c breakpoint.c findvar.c stack.c thread.c \
c-valprint.c cp-valprint.c ch-valprint.c f-valprint.c m2-valprint.c \
nlmread.c serial.c mdebugread.c os9kread.c top.c utils.c
YYSRCS= c-exp.y f-exp.y jv-exp.y m2-exp.y
-REMOTE_SRCS= remote.c dcache.c remote-utils.c tracepoint.c
+REMOTE_SRCS= remote.c dcache.c remote-utils.c tracepoint.c remote-ipkdb.c
DEPFILES= ${TDEPFILES.${MACHINE_ARCH}} ${XDEPFILES} ${SER_HARDWIRE} \
${NATDEPFILES} ${REMOTE_SRCS} ${SIM_SRCS}
diff --git a/gnu/usr.bin/gdb/remote-ipkdb.c b/gnu/usr.bin/gdb/remote-ipkdb.c
new file mode 100644
index 00000000000..110a9cf48f0
--- /dev/null
+++ b/gnu/usr.bin/gdb/remote-ipkdb.c
@@ -0,0 +1,753 @@
+/* Remote target communications for NetBSD targets via UDP (aka IPKDB).
+ Copyright (C) 1988-1991 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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 Foudation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that is 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 this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Remote communication protocol.
+
+ Data is sent in binary.
+ The first byte is the command code.
+
+ Packets have a sequence number and the data length prepended
+ and a signature appended. The signature is computed according
+ to the HMAC algorithm (see draft-ietf-ipsec-hmac-md5-00.txt).
+ The answer has the same sequence number. On a timeout, packets
+ are rerequested by resending the request.
+
+ Request Packet
+
+ read registers R
+ reply pXX...X Register data is sent in target format.
+ emessage for an error.
+
+ write regs WXX...X Same as above.
+ reply ok for success.
+ emessage for an error.
+
+ read mem MAA...ALL...L AA...A is address, LL...L is length
+ (both as CORE_ADDR).
+ reply pXX...X XX...X is mem contents.
+ emessage for an error.
+
+ write mem NAA...ALL...LXX...X
+ AA...A is address, LL...L is length,
+ XX...X is data.
+ reply ok for success.
+ emessage for an error.
+
+ cont C
+
+ step S
+
+ open debug OII...IWW...W II...I is an arbitrary id of the session,
+ WW...W is the user and machine running gdb.
+
+ There is no immediate reply to step, cont or open.
+ The reply comes when the machines stops (again).
+ It is s
+
+ detach X
+ reply ok
+*/
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "inferior.h"
+#include "target.h"
+#include "valprint.h"
+#include "wait.h"
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <md5.h>
+
+static struct target_ops ipkdb_ops;
+
+static int ipkdb_desc = -1;
+static char host[512];
+
+#define DBGPORT 1138
+
+#define PBUFSIZ 400
+
+static void remote_send();
+static void putpkt();
+static void getpkt();
+static int startprot();
+static void netread();
+static void netwrite();
+static void trykey();
+
+/* Clean up connection to remote debugger. */
+static void
+ipkdb_close(quitting)
+ int quitting;
+{
+ if (ipkdb_desc >= 0)
+ close(ipkdb_desc);
+ ipkdb_desc = -1;
+}
+
+/* Open a connection to a remote debugger.
+ The argument NAME, being the hostname of the target,
+ may optionally have the HMAC key for this appended. */
+static void
+ipkdb_open(name, from_tty)
+ char *name;
+ int from_tty;
+{
+ struct hostent *he;
+ struct sockaddr_in sin;
+
+ if (name == 0)
+ error(
+"To open a remote debug connection, you need to specify\n\
+the name of the target machine.");
+
+ trykey(name, from_tty);
+ strcpy(host, name);
+
+ ipkdb_close(0);
+
+ if (!(he = gethostbyname(host))
+ || he->h_addrtype != AF_INET)
+ error("host '%s' unknown\n", host);
+
+ target_preopen(from_tty);
+ push_target(&ipkdb_ops);
+
+ if ((ipkdb_desc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ perror_with_name(host);
+
+ sin.sin_len = sizeof sin;
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(DBGPORT);
+ sin.sin_addr = *(struct in_addr *)he->h_addr;
+
+ if (connect(ipkdb_desc, (struct sockaddr *)&sin, sizeof sin) < 0)
+ perror_with_name(host);
+
+ if (!catch_errors(startprot, NULL,
+ "Couldn't establish connection to remote target\n",
+ RETURN_MASK_ALL))
+ pop_target();
+ else if (from_tty)
+ printf_filtered("Remote debugging on %s\n", name);
+}
+
+/* Close the open connection to the remote debugger.
+ Use this when you want to detach and do something else
+ with your gdb. */
+static void
+ipkdb_detach(args, from_tty)
+ char *args;
+ int from_tty;
+{
+ char buf[PBUFSIZ];
+ int l;
+
+ *buf = 'X';
+ l = 1;
+ remote_send(buf, &l);
+ pop_target();
+ if (from_tty)
+ puts_filtered("Ending remote debugging IPKDB.\n");
+}
+
+/* Tell the remote machine to resume. */
+static void
+ipkdb_resume(pid, step, ssignal)
+ int pid, step;
+ enum target_signal ssignal;
+{
+ if (ssignal != TARGET_SIGNAL_0)
+ error("Can't send signals to a remote IPKDB system.");
+
+ putpkt(step ? "S" : "C", 1);
+}
+
+/* Wait until the remote machine stops, then return. */
+static int
+ipkdb_wait(pid, status)
+ int pid;
+ struct target_waitstatus *status;
+{
+ unsigned char buf[PBUFSIZ];
+ int l;
+
+ getpkt(buf, &l);
+ if (l > 0 && buf[0] == 'e') {
+ buf[l] = 0;
+ error("Remote failure reply: '%s'", buf + 1);
+ }
+ if (buf[0] != 's')
+ error("Invalid remote reply: '%s'", buf);
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+
+ return 0;
+}
+
+/* Read the remote registers. */
+static void
+ipkdb_fetch_register(regno)
+ int regno;
+{
+ char buf[PBUFSIZ];
+ int l;
+
+ *buf = 'R';
+ l = 1;
+ remote_send(buf, &l);
+
+ /* Reply describes registers byte by byte.
+ Suck them all up, and supply them to the
+ register cacheing/storage mechanism. */
+ for (l = 0; l < NUM_REGS; l++)
+ supply_register(l, &buf[1 + REGISTER_BYTE(l)]);
+}
+
+/* Prepare to store registers. Since we send them all, we have to
+ read out the ones we don't want to change first. */
+static void
+ipkdb_prepare_to_store()
+{
+ ipkdb_fetch_register(-1);
+}
+
+/* Store the remote registers. */
+static void
+ipkdb_store_register(regno)
+ int regno;
+{
+ char buf[PBUFSIZ];
+ int l;
+
+ buf[0] = 'W';
+
+ memcpy(buf + 1, registers, REGISTER_BYTES);
+ l = 1 + REGISTER_BYTES;
+
+ remote_send(buf, &l);
+}
+
+/* Put addr into buf */
+static void
+addrput(addr, buf)
+ CORE_ADDR addr;
+ char *buf;
+{
+ int i;
+
+ buf += sizeof addr;
+ for (i = sizeof addr; --i >= 0; addr >>= 8)
+ *--buf = addr;
+}
+
+/* Write memory data directly to the remote machine. */
+static void
+ipkdb_write_bytes(memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+
+ *buf = 'N';
+ addrput(memaddr, buf + 1);
+ addrput((CORE_ADDR)len, buf + 1 + sizeof(CORE_ADDR));
+
+ memcpy(buf + 1 + 2 * sizeof(CORE_ADDR), myaddr, len);
+
+ len += 1 + 2 * sizeof(CORE_ADDR);
+ remote_send(buf, &len);
+}
+
+/* Read memory data directly from the remote machine. */
+static void
+ipkdb_read_bytes(memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ char buf[PBUFSIZ];
+ int l;
+ char *p;
+
+ *buf = 'M';
+ addrput(memaddr, buf + 1);
+ addrput((CORE_ADDR)len, buf + 1 + sizeof(CORE_ADDR));
+
+ l = 1 + 2 * sizeof(CORE_ADDR);
+ remote_send(buf, &l);
+
+ if (l != len + 1)
+ error("ipkdb_read_bytes got wrong size of answer");
+
+ memcpy(myaddr, buf + 1, len);
+}
+
+/* Read or write LEN bytes from inferior memory at MEMADDR */
+static int
+ipkdb_xfer_memory(memaddr, myaddr, len, should_write, target)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+ int should_write;
+ struct target_ops *target;
+{
+ int origlen = len;
+ int xfersize;
+
+ while (len > 0) {
+ xfersize = min(len, PBUFSIZ - 3 * sizeof(CORE_ADDR));
+
+ if (should_write)
+ ipkdb_write_bytes(memaddr, myaddr, xfersize);
+ else
+ ipkdb_read_bytes(memaddr, myaddr, xfersize);
+ memaddr += xfersize;
+ myaddr += xfersize;
+ len -= xfersize;
+ }
+ return origlen;
+}
+
+static void
+ipkdb_files_info()
+{
+ printf_unfiltered("\tAttached to IPKDB at %s.\n", host);
+}
+
+static char bpt[] = BREAKPOINT;
+
+static int
+ipkdb_insert_breakpoint(addr, save)
+ CORE_ADDR addr;
+ char *save;
+{
+ ipkdb_read_bytes(addr, save, sizeof bpt);
+ ipkdb_write_bytes(addr, bpt, sizeof bpt);
+ return 0;
+}
+
+static int
+ipkdb_remove_breakpoint(addr, save)
+ CORE_ADDR addr;
+ char *save;
+{
+ ipkdb_write_bytes(addr, save, sizeof bpt);
+ return 0;
+}
+
+static void
+ipkdb_kill()
+{
+}
+
+/* Send the command in BUF to the remote machine,
+ and read the reply into BUF. */
+static void
+remote_send(buf, lp)
+ char *buf;
+ int *lp;
+{
+ putpkt(buf, *lp);
+ getpkt(buf, lp);
+
+ if (buf[0] == 'e') {
+ buf[*lp] = 0;
+ error("Remote failure reply: '%s'", buf + 1);
+ }
+}
+
+/* HMAC Checksumming routines */
+
+/*
+ * The following code is more or less stolen from the hmac_md5
+ * function in the Appendix of the HMAC IETF draft, but is
+ * optimized as suggested in this same paper.
+ */
+static char *key;
+static MD5_CTX icontext, ocontext;
+
+static void
+hmac_init()
+{
+ char pad[64];
+ char tk[16];
+ int key_len;
+ int i;
+
+ /* Require key to be at least 16 bytes long */
+ if (!key || (key_len = strlen(key)) < 16) {
+ if (key)
+ /* This doesn't make too much sense, but... */
+ memset(key, 0, key_len);
+
+ error("ipkdbkey must be at least 16 bytes long.");
+ }
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+ MD5Init(&icontext);
+ MD5Update(&icontext, key, key_len);
+ MD5Final(tk, &icontext);
+
+ /* This doesn't make too much sense, but... */
+ memset(key, 0, key_len);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is and n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+ /*
+ * We do the initial part of MD5(K XOR ipad)
+ * and MD5(K XOR opad) here, in order to
+ * speed up the computation later on.
+ */
+ memset(pad, 0, sizeof pad);
+ memcpy(pad, key, key_len);
+ for (i = 0; i < 64; i++)
+ pad[i] ^= 0x36;
+ MD5Init(&icontext);
+ MD5Update(&icontext, pad, 64);
+
+ memset(pad, 0, sizeof pad);
+ memcpy(pad, key, key_len);
+ for (i = 0; i < 64; i++)
+ pad[i] ^= 0x5c;
+ MD5Init(&ocontext);
+ MD5Update(&ocontext, pad, 64);
+
+ /*
+ * Zero out the key.
+ * This doesn't make too much sense, but...
+ */
+ memset(key, 0, key_len);
+}
+
+/*
+ * This is more or less hmac_md5 from the HMAC IETF draft, Appendix.
+ */
+static void *
+chksum(buf, len)
+ void *buf;
+ int len;
+{
+ static u_char digest[16];
+ struct MD5Context context;
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+ /*
+ * Since we've already done the precomputation,
+ * we can now stuff the data into the relevant
+ * preinitialized contexts to get the result.
+ */
+ /*
+ * perform inner MD5
+ */
+ memcpy(&context, &icontext, sizeof context);
+ MD5Update(&context, buf, len);
+ MD5Final(digest, &context);
+ /*
+ * perform outer MD5
+ */
+ memcpy(&context, &ocontext, sizeof context);
+ MD5Update(&context, digest, 16);
+ MD5Final(digest, &context);
+
+ return digest;
+}
+
+static struct cmd_list_element *setkeycmd;
+
+static void
+trykey(name, from_tty)
+ char *name;
+ int from_tty;
+{
+ char *k;
+
+ for (k = name; *k && !isspace(*k); k++);
+ if (*k)
+ *k++ = 0;
+ for (; *k && isspace(*k); k++);
+ if (*k)
+ do_setshow_command(k, from_tty, setkeycmd);
+ else if (!key)
+ error("No valid ipkdbkey yet");
+}
+
+/* net I/O routines */
+static long netseq;
+
+static long
+getnl(p)
+ void *p;
+{
+ u_char *s = p;
+
+ return (s[0] << 24)|(s[1] << 16)|(s[2] << 8)|s[3];
+}
+
+static int
+getns(p)
+ void *p;
+{
+ u_char *s = p;
+
+ return (s[0] << 8)|s[1];
+}
+
+static void
+setnl(p, l)
+ void *p;
+ long l;
+{
+ u_char *s = p;
+
+ *s++ = l >> 24;
+ *s++ = l >> 16;
+ *s++ = l >> 8;
+ *s = l;
+}
+
+static void
+setns(p, l)
+ void *p;
+ int l;
+{
+ u_char *s = p;
+
+ *s++ = l >> 8;
+ *s = l;
+}
+
+static int
+startprot(dummy)
+ char *dummy;
+{
+ char buf[PBUFSIZ];
+ char myname[128];
+
+ netseq = 0;
+
+ gethostname(myname, sizeof myname);
+ buf[0] = 'O';
+ setnl(buf + 1, time(NULL));
+ sprintf(buf + 5, "%s@%s", getlogin(), myname);
+ putpkt(buf, 5 + strlen(buf + 5));
+
+ /* Don't print character strings by default. This might break the target. */
+ print_max = 0;
+
+ start_remote();
+
+ return 1;
+}
+
+static char ibuf[512], obuf[512];
+static int olen;
+
+static void
+putpkt(buf, len)
+ char *buf;
+ int len;
+{
+ if (len > sizeof obuf - 10)
+ error("putpkt: packet too large");
+
+ setnl(obuf, netseq);
+ setns(obuf + 4, len);
+ memcpy(obuf + 6, buf, len + 1);
+ memcpy(obuf + len + 6, chksum(obuf, len + 6), 16);
+ olen = len + 6 + 16;
+
+ if (write(ipkdb_desc, obuf, olen) < 0
+ && (errno != EINTR
+#ifdef ECONNREFUSED
+ && errno != ECONNREFUSED
+#endif
+#ifdef EHOSTDOWN
+ && errno != EHOSTDOWN
+#endif
+ ))
+ fatal("putpkt: write");
+}
+
+static void
+getpkt(buf, lp)
+ char *buf;
+ int *lp;
+{
+ int len;
+ struct timeval tv, deadline;
+ fd_set rd;
+
+ gettimeofday(&deadline, NULL);
+ deadline.tv_sec++;
+
+ while (1) {
+ notice_quit();
+ if (quit_flag)
+ quit();
+
+ FD_ZERO(&rd);
+ FD_SET(ipkdb_desc, &rd);
+ gettimeofday(&tv, NULL);
+ tv.tv_sec = deadline.tv_sec - tv.tv_sec;
+ tv.tv_usec = deadline.tv_usec - tv.tv_usec;
+ if (tv.tv_usec < 0) {
+ tv.tv_usec += 1000000;
+ tv.tv_sec--;
+ }
+ if (tv.tv_sec < 0)
+ tv.tv_sec = tv.tv_usec = 0;
+ switch (select(ipkdb_desc + 1, &rd, NULL, NULL, &tv)) {
+ case -1:
+ if (errno == EINTR
+#ifdef ECONNREFUSED
+ || errno == ECONNREFUSED /* Solaris lossage??? */
+#endif
+ )
+ continue;
+ fatal("getpkt: select");
+ default:
+ if (read(ipkdb_desc, ibuf, sizeof ibuf) < 0) {
+ if (errno == EINTR
+#ifdef ECONNREFUSED
+ || errno == ECONNREFUSED /* Solaris lossage??? */
+#endif
+ )
+ continue;
+ fatal("getpkt: recvfrom");
+ }
+ if (getnl(ibuf) != netseq)
+ break;
+ len = getns(ibuf + 4);
+ if (!memcmp(chksum(ibuf, len + 6), ibuf + 6 + len, 16)) {
+ netseq++;
+ memcpy(buf, ibuf + 6, len);
+ *lp = len;
+ return;
+ }
+ /*
+ * Packet had correct sequence number, but
+ * wrong checksum, do an immediate retry, so...
+ */
+ /* FALLTHROUGH */
+ case 0:
+ if (write(ipkdb_desc, obuf, olen) < 0) {
+ if (errno == EINTR
+#ifdef ECONNREFUSED
+ || errno == ECONNREFUSED /* Solaris lossage??? */
+#endif
+ )
+ continue;
+ fatal("getpkt: write");
+ }
+ gettimeofday(&deadline, NULL);
+ deadline.tv_sec++;
+ break;
+ }
+ }
+}
+
+/* Defint the target subroutine names */
+static struct target_ops ipkdb_ops = {
+ "ipkdb",
+ "Remote IPKDB target via UDP/IP",
+ "Debug a remote computer via UDP/IP.\n\"
+Specify the name of the target machine",
+ ipkdb_open,
+ ipkdb_close,
+ 0, /* attach */
+ ipkdb_detach,
+ ipkdb_resume,
+ ipkdb_wait,
+ ipkdb_fetch_register,
+ ipkdb_store_register,
+ ipkdb_prepare_to_store,
+ ipkdb_xfer_memory,
+ ipkdb_files_info,
+ ipkdb_insert_breakpoint,
+ ipkdb_remove_breakpoint,
+ 0, /* terminal_init */
+ 0, /* terminal_inferior */
+ 0, /* terminal_ours_for_output */
+ 0, /* terminal_ours */
+ 0, /* terminal_info */
+ ipkdb_kill,
+ 0, /* load */
+ 0, /* lookup_symbol */
+ 0, /* create_inferior */
+ 0, /* mourn_inferior */
+ 0, /* can_run */
+ 0, /* notice_signals */
+ 0, /* thread_alive */
+ 0, /* stop */
+ process_stratum, /* stratum */
+ 0, /* next (unused) */
+ 1, /* has_all_memory */
+ 1, /* has_memory */
+ 1, /* has_stack */
+ 1, /* has_registers */
+ 1, /* has_execution */
+ 0, /* sections */
+ 0, /* sections_end */
+ OPS_MAGIC /* Always the last thing */
+};
+
+void
+_initialize_ipkdb()
+{
+ add_target(&ipkdb_ops);
+
+ setkeycmd = add_set_cmd("ipkdbkey", class_support, var_string,
+ (char *)&key,
+ "Set the key to be used for authentication of IPKDB debugging.\n\
+The key given must be at least 16 bytes in length.",
+ &setlist);
+ setkeycmd->function.sfunc = hmac_init;
+}