diff options
| author | ws <ws@NetBSD.org> | 2000-03-23 20:44:40 +0000 |
|---|---|---|
| committer | ws <ws@NetBSD.org> | 2000-03-23 20:44:40 +0000 |
| commit | 0bb2093748a706e3290c27dbcd4f5d20fa6ebaa6 (patch) | |
| tree | 3eed7bea9aad03a5dbd43e649350962a4abe2c5a /gnu/usr.bin | |
| parent | 7c8b72d5927d38b58563c44b2ab19aee400bc47a (diff) | |
Add IPKDB support to GDB.
Diffstat (limited to 'gnu/usr.bin')
| -rw-r--r-- | gnu/usr.bin/gdb/Makefile | 4 | ||||
| -rw-r--r-- | gnu/usr.bin/gdb/remote-ipkdb.c | 753 |
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; +} |
