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
|