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