2000-08-07 19:20:36 +04:00
|
|
|
|
/* $NetBSD: remote-ipkdb.c,v 1.3 2000/08/07 15:20:36 ws Exp $ */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Part of this code is derived from software copyrighted by the
|
|
|
|
|
* Free Software Foundation.
|
|
|
|
|
*
|
|
|
|
|
* Modified 1993-2000 by Wolfgang Solfrank.
|
|
|
|
|
*/
|
|
|
|
|
|
2000-03-23 23:44:40 +03:00
|
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-27 20:31:05 +04:00
|
|
|
|
#ifdef BREAKPOINT
|
2000-03-23 23:44:40 +03:00
|
|
|
|
static char bpt[] = BREAKPOINT;
|
2000-03-27 20:31:05 +04:00
|
|
|
|
#endif
|
2000-03-23 23:44:40 +03:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ipkdb_insert_breakpoint(addr, save)
|
|
|
|
|
CORE_ADDR addr;
|
|
|
|
|
char *save;
|
|
|
|
|
{
|
2000-03-27 20:31:05 +04:00
|
|
|
|
#ifdef BREAKPOINT
|
2000-03-23 23:44:40 +03:00
|
|
|
|
ipkdb_read_bytes(addr, save, sizeof bpt);
|
|
|
|
|
ipkdb_write_bytes(addr, bpt, sizeof bpt);
|
|
|
|
|
return 0;
|
2000-03-27 20:31:05 +04:00
|
|
|
|
#else
|
|
|
|
|
error("Don't know how to insert breakpoint");
|
|
|
|
|
#endif
|
2000-03-23 23:44:40 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
ipkdb_remove_breakpoint(addr, save)
|
|
|
|
|
CORE_ADDR addr;
|
|
|
|
|
char *save;
|
|
|
|
|
{
|
2000-03-27 20:31:05 +04:00
|
|
|
|
#ifdef BREAKPOINT
|
2000-03-23 23:44:40 +03:00
|
|
|
|
ipkdb_write_bytes(addr, save, sizeof bpt);
|
|
|
|
|
return 0;
|
2000-03-27 20:31:05 +04:00
|
|
|
|
#else
|
|
|
|
|
error("Don't know how to remove breakpoint");
|
|
|
|
|
#endif
|
2000-03-23 23:44:40 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|