WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-ppc-devel

[XenPPC] [RFC][PATCH] Add SOL proxy to xen/tools.

To: XenPPC-devel <xen-ppc-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [XenPPC] [RFC][PATCH] Add SOL proxy to xen/tools.
From: Tony Breeds <tony@xxxxxxxxxxxxxxxxxx>
Date: Fri, 22 Sep 2006 15:07:54 +1000
Delivery-date: Thu, 21 Sep 2006 22:08:18 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-ppc-devel-request@lists.xensource.com?subject=help>
List-id: Xen PPC development <xen-ppc-devel.lists.xensource.com>
List-post: <mailto:xen-ppc-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-ppc-devel>, <mailto:xen-ppc-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-ppc-devel>, <mailto:xen-ppc-devel-request@lists.xensource.com?subject=unsubscribe>
Mail-followup-to: XenPPC-devel <xen-ppc-devel@xxxxxxxxxxxxxxxxxxx>
Sender: xen-ppc-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.9i
From: Tony Breeds <tony@xxxxxxxxxxxxxxxxxx>

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

Signed-off-by: Tony Breeds <tony@xxxxxxxxxxxxxxxxxx>

---
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:
+       -@$(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@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-ppc-devel

<Prev in Thread] Current Thread [Next in Thread>
  • [XenPPC] [RFC][PATCH] Add SOL proxy to xen/tools., Tony Breeds <=