From: Tony Breeds <[EMAIL PROTECTED]>

Add Utilisities to connect to thr SOL console of a blade for use with
GDB.

Signed-off-by: Tony Breeds <[EMAIL PROTECTED]>

---
Tested (lots) on a JS20

 tools/gdbproxy/Makefile      |   34 ++++
 tools/gdbproxy/README        |   49 ++++++
 tools/gdbproxy/SOL-connect.c |  332 +++++++++++++++++++++++++++++++++++++++++++
 tools/gdbproxy/debug.c       |   82 ++++++++++
 tools/gdbproxy/debug.h       |   18 ++
 tools/gdbproxy/exec.c        |  104 +++++++++++++
 tools/gdbproxy/exec.h        |    5 
 tools/gdbproxy/gdbproxy.c    |  273 +++++++++++++++++++++++++++++++++++
 8 files changed, 897 insertions(+)
---
diff -r 91ee784bc367 tools/gdbproxy/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdbproxy/Makefile   Fri Sep 22 14:42:41 2006 +1000
@@ -0,0 +1,34 @@
+CC     =       gcc
+CFLAGS =       -Wall -Wextra -Werror -O0 -g
+CFLAGS +=      -Wp,-MD,.$(@F).d
+#CFLAGS        +=      -DDEBUG
+#CFLAGS +=     -DWITH_TIMEOUT
+LFLAGS =
+CMDS   =       gdbproxy SOL-connect
+
+PROG_DEP = .*.d
+
+.PHONY: all
+all: $(CMDS)
+
+%.o:%.c
+       $(CC) $(CFLAGS) -c $<
+
+gdbproxy: gdbproxy.o debug.o exec.o
+       $(CC) $(LFLAGS) -o $@ $^
+
+SOL-connect: SOL-connect.o debug.o exec.o
+       $(CC) $(LFLAGS) -o $@ $^
+
+
+.PHONY: cscope
+cscope: cscope.out
+cscope.out: $(SRC)
+       /usr/bin/cscope -b $^
+
+.PHONY: clean
+clean:
+       [EMAIL PROTECTED](RM) $(CMDS) *.o .*.d cscope.out .*log *log 
+
+
+-include $(PROG_DEP)
diff -r 91ee784bc367 tools/gdbproxy/README
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdbproxy/README     Fri Sep 22 14:42:41 2006 +1000
@@ -0,0 +1,49 @@
+This directory contains two utilities for connecting GDB to Xen
+waiting for GDB to connect.
+
+ ### SOL-connect ###
+
+Connects to the Serial Over LAN (SOL) console of a given blade.
+SOL-connect takes the following arguments.
+---
+SOL-connect -u username -P password -s server -p port -b blade_index
+       -u       username to auto login with
+       -P       password to auto login with
+       -s       name of the blade management module
+       -p       port to connect on [default: 23]
+       -b       index in system:blade[] for the blade
+---
+An example setup:
+
+~/bin/gdb-remote :
+-----------------+
+#!/bin/bash
+
+exec /home/tony/src/gdbproxy/SOL-connect -s blademm1 -u X -P X -b 4
+---
+
+It's important to set GDB to have a large timeout "0" means infinite. To do
+this create a .gdbinit file like the one below.
+
+~/.gdbinit :
+-----------+
+set remotetimeout 0
+show remotetimeout
+---
+
+Then invoke GDB and connect to the console.
+$ gdb xen/xen-syms
+(gdb) target remote |~/bin/gdb-connect
+
+Assuming the blade is sitting at a "(XEN) Waiting for GDB to attach..."
+prompt, the debugger will drop :1
+
+ ### gdbproxy ###
+
+gdpproxy spawns an application (passed in via the PROXY_COMMAND environment
+variable), gdbproxy then listens on port 1234.  This is needed when the
+debugger cannot directly access the blade.
+
+ ### Known bugs ###
+
+None.
diff -r 91ee784bc367 tools/gdbproxy/SOL-connect.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdbproxy/SOL-connect.c      Fri Sep 22 14:42:41 2006 +1000
@@ -0,0 +1,332 @@
+/******************************************************************************
+ * SOL-connect.c
+ *
+ * Dirty hack to login to a blade management module and connect to a console
+ * waiting for a GDB to attach.  Very Xen specific
+ *
+ * Copyright (C) 2006 Tony Breeds, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <err.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "exec.h"
+#include "debug.h"
+
+#define __unused       __attribute__((unused))
+
+#define PROGRAM_NAME   "SOL-connect"
+#define PROXY_PRG      "/usr/bin/telnet"
+
+typedef uint8_t byte;
+
+static pid_t telnet_pid = -1;
+static int remote_in;
+static int remote_out;
+static int local_in;
+static int local_out;
+
+static struct expect {
+       char *expect;
+       char *send;
+} expects[] = {
+       { .expect = "username: ", .send   = NULL },
+       { .expect = "password: ", .send   = NULL },
+       { .expect = "system> ",   .send   = NULL },
+       { .expect = "\x1b[2J",    .send   = NULL },
+       { NULL, NULL}
+};
+static int next_expect = 0;
+static bool needs_eol_hack = true;
+static bool last_packet_was_ack = false;
+
+/* Force an ACK just in case */
+static void force_ack(int arg __unused)
+{
+       const char buf[] = "+";
+
+       if (!last_packet_was_ack)
+               write(remote_out, &buf, 1);
+}
+
+static void usage(void)
+{
+       fprintf(stderr, "%s -u username -P password -s server -p port "
+                       "-b blade_index\n", PROGRAM_NAME);
+       fprintf(stderr, "\t-u\t username to auto login with\n");
+       fprintf(stderr, "\t-P\t password to auto login with\n");
+       fprintf(stderr, "\t-s\t name of the blade management module\n");
+       fprintf(stderr, "\t-p\t port to connect on [default: 23]\n");
+       fprintf(stderr, "\t-b\t index in system:blade[] for the blade\n");
+       exit(1);
+}
+
+static void setup_expects(const char *un, const char *pw, const char *idx)
+{
+       const char eol[] = "\r\n";
+       char *tmp;
+
+       tmp = malloc(strlen(un) + strlen(eol));
+       tmp = strncpy(tmp, un, strlen(un));
+       tmp = strncat(tmp, eol, strlen(eol));
+       expects[0].send = tmp;
+
+       tmp = malloc(strlen(pw) + strlen(eol));
+       tmp = strncpy(tmp, pw, strlen(pw));
+       tmp = strncat(tmp, eol, strlen(eol));
+       expects[1].send = tmp;
+
+       /* FIMXE: too much but what they hey */
+       tmp = calloc(4096, sizeof(char));
+       sprintf(tmp, "console -T system:blade[%s] -o%s", idx, eol);
+       expects[2].send = tmp;
+}
+
+static void run_telnet(char *server, char *port)
+{
+       int ret;
+       size_t len;
+       char buf[4096];
+
+       /* FIXME: is SOL 8-bit clean? */
+       len = sprintf(buf, "%s -8 %s %s", PROXY_PRG, server, port);
+       ret = run_cmd(buf, &remote_out, &remote_in);
+       if (ret < 0)
+               err(1, "Running Telnet failed");
+       telnet_pid = ret;
+
+       return;
+}
+
+static void do_eol_hack(int *in_len, uint8_t* in_buf, uint8_t *out_buf)
+{
+       int i,j;
+
+       if (needs_eol_hack) {
+               /* Yck insert a \r before every \n unless it's there */
+               for(i=0,j=0; i<=*in_len; i++, j++) {
+                       if (in_buf[i] == '\n' && in_buf[i-1] != '\r') {
+                               out_buf[j++] = '\r';
+                       }
+                       out_buf[j] = in_buf[i];
+               }
+               *in_len = j;
+       } else {
+               memcpy(out_buf, in_buf, *in_len);
+       }
+
+       return;
+}
+
+static int data_from_user(void)
+{
+        bool more = true;
+        uint8_t buf[4096];
+        uint8_t buf2[4096];
+        int in_len, out_len;
+       int infd = local_in, outfd = remote_out;
+
+        while (more) {
+               memset(buf,  0, sizeof(buf) );
+               memset(buf2, 0, sizeof(buf2));
+
+                in_len = read(infd, buf, sizeof(buf));
+               if (in_len < 0) {
+                       warn("Read from %d returned %d", infd, in_len);
+                       more = false;
+               } else {
+                       more = (in_len == sizeof(buf));
+                       debug_log_data("Read", infd, buf, out_len);
+                       /* FIXME: Potential Overrun */
+                       do_eol_hack(&in_len, buf, buf2);
+                       out_len = write(outfd, buf2, in_len);
+                       if (out_len != in_len)
+                               warn("Short write to fd(%d)", outfd);
+
+                       debug_log_data("Writing", outfd, buf2, out_len);
+                       last_packet_was_ack = (out_len == 1 && buf2[0] == '+');
+               }
+        }
+
+        return in_len;
+}
+
+static void do_expect(uint8_t *in_buf)
+{
+       int out_len;
+       int send_len;
+       uint8_t out_buf[4096];
+
+       if (expects[next_expect].expect == NULL)
+               return;
+
+       /* Yck! */
+       if (strstr((char*)in_buf, expects[next_expect].expect)) {
+               if (expects[next_expect].send) {
+                       send_len = strlen(expects[next_expect].send);
+
+                       memcpy(out_buf, expects[next_expect].send, send_len);
+                       out_len = write(remote_out, out_buf, send_len);
+                       if (out_len != send_len)
+                               warn("Short write in expect!");
+               }
+               next_expect++;
+               /* Assume when we get to the end of the expect script that
+                * we're happy */
+               needs_eol_hack = (expects[next_expect].expect != NULL);
+       }
+
+       return;
+}
+
+static int data_from_remote(void)
+{
+        bool more = true;
+       uint8_t buf[4096];
+        int in_len, out_len;
+       int infd = remote_in, outfd = local_out;
+
+        while (more) {
+                in_len = read(infd, buf, sizeof(buf));
+               if (in_len < 0) {
+                       warn("Read from %d returned %d", infd, in_len);
+                       more = false;
+               } else {
+                       more = (in_len == sizeof(buf));
+                       debug_log_data("Read", infd, buf, in_len);
+                       out_len = write(outfd, buf, in_len);
+                       if (out_len != in_len)
+                               warn("Short write to fd(%d)", outfd);
+                       debug("Wrote %d bytes to terminal(%d)", out_len, outfd);
+                       do_expect(buf);
+                       debug_log_data("Writing", outfd, buf, out_len);
+               }
+        }
+
+        return in_len;
+}
+
+int main(int argc, char **argv)
+{
+       fd_set fds;
+       int opt, ret;
+       char *port = "23";
+       struct timeval *timeout = NULL;
+       sighandler_t old_sigterm;
+       char *server = NULL, *username = NULL, *password = NULL,
+            *blade_idx = NULL;
+
+       debug_init(".SOL-connect.log");
+
+       while ( (opt = getopt(argc, argv, "s:p:u:P:b:")) != EOF) {
+               switch(opt) {
+               case 's':
+                       server = optarg;
+                       break;
+               case 'p':
+                       port = optarg;
+                       break;
+               case 'u':
+                       username = optarg;
+                       break;
+               case 'P':
+                       password = optarg;
+                       break;
+               case 'b':
+                       blade_idx = optarg;
+                       break;
+               default:
+                       errx(1, "Unknown ARG '%s'", optarg);
+               }
+       }
+
+       /* Keep argc and argv in sync for old times sake */
+       argv += optind;
+       argc -= optind;
+       if (argc > 0)
+               usage();
+
+       if (!server && !username && !password && !blade_idx)
+               usage();
+
+       setbuf(stdin, NULL);
+       setbuf(stdout, NULL);
+       local_in = fileno(stdin);
+       local_out = fileno(stdout);
+
+       old_sigterm = signal(SIGTERM, force_ack);
+       if (old_sigterm == SIG_ERR)
+               warnx("Failed to register signal handler");
+       setup_expects(username, password, blade_idx);
+       run_telnet(server, port);
+
+#ifdef WITH_TIMEOUT
+       timeout = calloc(1, sizeof(*timeout));
+#endif
+       /* FIXME: Really shouldn't send any data to local_out, until
+        * after the expect script is complete */
+       do {
+               FD_ZERO(&fds);
+               /* Don't read fron local_in, until after connected to the
+                * console */
+               if (!needs_eol_hack)
+                       FD_SET(local_in, &fds);
+               FD_SET(remote_in, &fds);
+
+#ifdef WITH_TIMEOUT
+               timeout->tv_sec=5;
+               timeout->tv_usec=0;
+#endif
+
+               ret = select(getdtablesize(), &fds, NULL, NULL, timeout);
+               /* FIXME: general robustness */
+               if (ret == -1)
+                       err(1, "select()");
+               else if (!ret)
+                       errx(1, "Timeout!!");
+
+               if (FD_ISSET(local_in, &fds))
+                       ret = data_from_user();
+               else if (FD_ISSET(remote_in, &fds))
+                       ret = data_from_remote();
+       } while (ret != 0);
+
+       /* FIXME: Clean up */
+       return 0;
+}
diff -r 91ee784bc367 tools/gdbproxy/debug.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdbproxy/debug.c    Fri Sep 22 14:42:41 2006 +1000
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * debug.c
+ *
+ * Generic debug routines for the gdbproxy and SOL-connect
+ *
+ * Copyright (C) 2006 Tony Breeds, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "debug.h"
+
+#ifdef DEBUG
+
+static int debug_fd;
+
+void debug_init(const char *file_name)
+{
+       int len;
+       char buf[4096];
+
+       debug_fd = open(file_name, O_CREAT|O_TRUNC|O_SYNC|O_WRONLY, 
+                       S_IRUSR|S_IWUSR);
+       if (debug_fd < 0)
+               err(1, "Couldn't opne debug logfile");
+       /* FIXME: Add timestamp */
+       len = sprintf(buf, "Log opened\n");
+       write(debug_fd, buf, len);
+}
+
+void debug_log_data(char *msg, int fd, uint8_t *buf, int buf_len)
+{
+       int len;
+       char header[4096];
+
+       /* Skip bogus data */
+       if (buf_len == 1 && buf[0] == '\x0')
+               return;
+
+       len = sprintf(header, "\n%s(%d) %d bytes : ", msg, fd, buf_len);
+       write(debug_fd, header, len);
+       write(debug_fd, buf, buf_len);
+       fdatasync(debug_fd);
+}
+
+#endif
diff -r 91ee784bc367 tools/gdbproxy/debug.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdbproxy/debug.h    Fri Sep 22 14:42:41 2006 +1000
@@ -0,0 +1,18 @@
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#ifdef DEBUG
+/* FIXME: include program name */
+#define debug(fmt, ...)        ({                                              
      \
+   fprintf(stderr, "%s().%d: " fmt "\n", __func__, __LINE__, ## __VA_ARGS__); \
+   fflush(stderr);                                                            \
+})
+extern void debug_init(const char *);
+extern void debug_log_data(char *msg, int fd, uint8_t *buf, int buf_len);
+#else
+#define debug(fmt, ...)        do {} while(0)
+#define debug_init(x)  do {} while(0)
+#define debug_log_data(...) do {} while(0)
+#endif
+
+#endif  /* __DEBUG_H__ */
diff -r 91ee784bc367 tools/gdbproxy/exec.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdbproxy/exec.c     Fri Sep 22 14:42:41 2006 +1000
@@ -0,0 +1,104 @@
+/******************************************************************************
+ * exec.c
+ *
+ * Spawn a program for bi-directional comms, both gdbproxy and SOL-connect need
+ * to do this.
+ *
+ * Copyright (C) 2006 Tony Breeds, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "exec.h"
+#include "debug.h"
+
+#define BASH_PATH      "/bin/bash"
+
+int run_cmd(const char *cmd, int *to_cmd, int *from_cmd)
+{
+       pid_t pid;
+       size_t len;
+       char buf[4096];
+       int pin[2], pout[2];
+
+       len = sprintf(buf, "%s %s", "exec", cmd);
+
+       if (pipe(pin) < 0 || pipe(pout) < 0)
+               err(1, "Creating pipes failed");
+
+       debug("Executing proxy command: %.500s", buf);
+       pid = fork();
+       if (pid == 0) {
+               char *argv[4];
+
+               /* Redirect stdin and stdout. */
+               close(pin[1]);
+               if (pin[0] != 0) {
+                       if (dup2(pin[0], 0) < 0)
+                               warn("dup2 stdin");
+                       close(pin[0]);
+               }
+               close(pout[0]);
+               if (dup2(pout[1], 1) < 0)
+                       warn("dup2 stdout");
+               close(pout[1]);
+
+               /* Leave stderr alone */
+               argv[0] = BASH_PATH;
+               argv[1] = "-c";
+               argv[2] = buf;
+               argv[3] = NULL;
+
+               execv(argv[0], argv);
+               return -1;
+       }
+
+       /* Parent. */
+       if (pid < 0)
+               err(1, "fork() barfed!");
+
+       /* Close child side of the descriptors. */
+       close(pin[0]);
+       close(pout[1]);
+
+       *from_cmd = pout[0];
+       *to_cmd = pin[1];
+
+       return pid;
+}
diff -r 91ee784bc367 tools/gdbproxy/exec.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdbproxy/exec.h     Fri Sep 22 14:42:41 2006 +1000
@@ -0,0 +1,5 @@
+#ifndef __EXEC_H__
+#define __EXEC_H__
+
+extern int run_cmd(const char *cmd, int *to_cmd, int *from_cmd);
+#endif  /* __EXEC_H__ */
diff -r 91ee784bc367 tools/gdbproxy/gdbproxy.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdbproxy/gdbproxy.c Fri Sep 22 14:42:41 2006 +1000
@@ -0,0 +1,273 @@
+/******************************************************************************
+ * gdbproxy.c
+ *
+ * Spawn a command that will connect to a Xen machine waiting for GDB.
+ * Once established, listen on port 1234 for a GDB process to conenct.
+ * shvel data between the 2.
+ *
+ * Copyright (C) 2006 Tony Breeds, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "exec.h"
+#include "debug.h"
+
+/* FIXME: This shouldn't be a compile time setting */
+#ifndef DEFAULT_PROXY
+#define DEFAULT_PROXY "/home/tony/bin/gdb-remote"
+#endif
+
+#define status(fmt, ...)       fprintf(stderr, fmt "\n", ## __VA_ARGS__)
+
+static int gdb_socket = 0;
+static int from_proxy = -1, to_proxy = -1;
+
+static int data_from_gdb(void)
+{
+        bool more = true;
+        uint8_t buf[4096];
+        int in_len, out_len;
+       int infd = gdb_socket, outfd = to_proxy;
+
+        while (more) {
+               memset(buf,  0, sizeof(buf) );
+
+                in_len = read(infd, buf, sizeof(buf));
+               if (in_len < 0) {
+                       warn("Read from %d returned %d", infd, in_len);
+                       more = false;
+               } else {
+                       debug("Read %d bytes from gdb(%d)", in_len, infd);
+                       more = (in_len == sizeof(buf));
+                       debug_log_data("Read", infd, buf, in_len);
+
+                       out_len = write(outfd, buf, in_len);
+                       if (out_len != in_len)
+                               warn("Short write to fd(%d)", outfd);
+
+                       debug("Wrote %d bytes to hw(%d)", out_len, outfd);
+                       debug_log_data("Writing", outfd, buf, out_len);
+               }
+        }
+
+        return in_len;
+}
+
+
+static int data_from_hw(void)
+{
+        bool more = true;
+       uint8_t buf[4096];
+        int in_len, out_len;
+       int outfd = gdb_socket, infd = from_proxy;
+
+        while (more) {
+                in_len = read(infd, buf, sizeof(buf));
+               debug("Read %d bytes from hw(%d)", in_len, infd);
+               more = (in_len == sizeof(buf));
+               if (in_len < 0) {
+                       warn("Read from %d returned %d", infd, in_len);
+                       more = false;
+               } else {
+                       debug_log_data("Read", infd, buf, in_len);
+
+                       out_len = write(outfd, buf, in_len);
+                       if (out_len != in_len)
+                               warn("Short write to fd(%d)", outfd);
+
+                       debug("Wrote %d bytes to gdb(%d)", out_len, outfd);
+                       debug_log_data("Writing", outfd, buf, out_len);
+               }
+        }
+
+        return in_len;
+}
+
+static int listen_on(int port)
+{
+       int ret;
+       int sock;
+       int on = 1;
+       struct sockaddr_in sin;
+
+       memset(&sin, 0, sizeof(sin));
+
+       sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if (sock < 0)
+               err(1, "port %d socket() error", port);
+
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(INADDR_ANY);
+       sin.sin_port = htons(port);
+
+       ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+       if (ret)
+               err(1, "port %d setsockopt() error", port);
+       ret = bind(sock, (struct sockaddr *)&sin,  sizeof(sin));
+       if (ret)
+               err(1, "port %d bind() error", port);
+       ret = listen(sock, 0);
+       if (ret)
+               err(1, "port %d listen() error", port);
+       ret = fcntl(sock, F_SETFL, O_NDELAY);
+       if (ret < 0)
+               err(1, "port %d fcntl() error", port);
+
+       return sock;
+}
+
+static int init_server(int port)
+{
+       int fd;
+       int sock;
+       socklen_t len;
+       struct sockaddr_in sin;
+
+       sock = listen_on(port);
+
+       fd = -1;
+
+       do {
+               sleep(1);
+               len = sizeof(sin);
+               fd = accept(sock, (struct sockaddr*)&sin, &len);
+       } while (fd == -1);
+
+       return fd;
+}
+
+/* Wait for the console to be ready */
+/* FIXME: Yck!  This really should be done by the proxy command */
+static void wait_for_connect(void)
+{
+       int in_len;
+       int len = 0;
+       char *found;
+       uint8_t buf[4096];
+       char needle[] = " for help]";
+
+       /* Build up the input from the hw until we see needle */
+       do {
+               in_len = read(from_proxy, &buf[len], sizeof(buf) - len);
+               if (in_len < 0)
+                       err(1, "%s() read from hw failed", __func__);
+               found = strstr((char*)buf, needle);
+       } while (!found);
+
+       return;
+}
+
+static void run_proxy(void)
+{
+       int ret;
+       char *cmd;
+
+       cmd = getenv("PROXY_COMMAND");
+       ret = run_cmd((cmd?cmd:DEFAULT_PROXY), &to_proxy, &from_proxy);
+       if (ret < 0)
+               err(1, "Failed to run proxy \"%s\"", (cmd?cmd:DEFAULT_PROXY));
+
+       /* FIXME: This need to be generic */
+       /* If we're using the dafault proxy then wait for it to be ready
+        * (it's slow) */
+       if (!cmd) {
+               /* Give the slow console a change to esablish */
+               status("Sleeping on proxy");
+               sleep(10);
+               status("Waiting for hardware");
+               wait_for_connect();
+       }
+
+       return;
+}
+
+
+int main(void)
+{
+       int ret;
+       fd_set fds;
+       struct timeval *timeout = NULL;
+
+       debug_init(".gdbproxy.log");
+
+       status("Launching proxy");
+       run_proxy();
+       status("Launching Server [connect GDB now]");
+       gdb_socket = init_server(1234);
+       status("Ready");
+
+       debug("fd(%d) == gdb_socket", gdb_socket);
+       debug("fd(%d) == from_proxy", from_proxy);
+       debug("fd(%d) == to_proxy", to_proxy);
+
+#ifdef WITH_TIMEOUT
+       timeout = calloc(1, sizeof(*timeout));
+#endif
+       setbuf(stdin, NULL);
+       do {
+               FD_ZERO(&fds);
+               FD_SET(gdb_socket, &fds);
+               FD_SET(from_proxy, &fds);
+
+#ifdef WITH_TIMEOUT
+               timeout->tv_sec=15;
+               timeout->tv_usec=0;
+#endif
+               ret = select(getdtablesize(), &fds, NULL, NULL, timeout);
+               /* FIXME: general robustness */
+               if (ret == -1)
+                       err(1, "select()");
+               else if (!ret)
+                       errx(1, "Timeout!!");
+
+               if (FD_ISSET(gdb_socket, &fds))
+                       ret = data_from_gdb();
+               else if (FD_ISSET(from_proxy, &fds))
+                       ret = data_from_hw();
+       } while (ret != 0);
+
+       /* FIXME: Clean up */
+       return 0;
+}


Yours Tony

   linux.conf.au       http://linux.conf.au/ || http://lca2007.linux.org.au/
   Jan 15-20 2007      The Australian Linux Technical Conference!


_______________________________________________
Xen-ppc-devel mailing list
Xen-ppc-devel@lists.xensource.com
http://lists.xensource.com/xen-ppc-devel

Reply via email to