From 47d044934727c3d5a57658ddd324b407dd73860a Mon Sep 17 00:00:00 2001 From: ntfreak Date: Mon, 15 Dec 2008 09:43:26 +0000 Subject: - add ability for openocd to communicate to gdb using pipes (stdin/stdout). - this is enabled by new command line option option --pipe. git-svn-id: svn://svn.berlios.de/openocd/trunk@1242 b42882b7-edfa-0310-969c-e2dbd0fdcd60 --- src/helper/Makefile.am | 2 +- src/helper/log.c | 19 ++++- src/helper/options.c | 28 +++++-- src/server/gdb_server.c | 70 +++++++++++------ src/server/server.c | 192 +++++++++++++++++++++++++++++---------------- src/server/server.h | 7 +- src/server/tcl_server.c | 2 +- src/server/telnet_server.c | 2 +- src/target/target.c | 7 +- 9 files changed, 220 insertions(+), 109 deletions(-) (limited to 'src') diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index d81e7d20..9162d5fc 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES = -I$(top_srcdir)/src $(all_includes) -I$(top_srcdir)/src/target +INCLUDES = -I$(top_srcdir)/src $(all_includes) -I$(top_srcdir)/src/target -I$(top_srcdir)/src/server METASOURCES = AUTO AM_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" -DPKGLIBDIR=\"$(pkglibdir)\" @CPPFLAGS@ noinst_LIBRARIES = libhelper.a diff --git a/src/helper/log.c b/src/helper/log.c index d21b8e9f..8e320084 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -31,6 +31,7 @@ #include "configuration.h" #include "time_support.h" #include "command.h" +#include "server.h" #include #include @@ -108,9 +109,11 @@ static void log_puts(enum log_levels level, const char *file, int line, const ch #endif string); } - else + else if(server_use_pipes == 0) { - if (strcmp(string, "\n")!=0) + /* if we are using gdb through pipes then we do not want any output + * to the pipe otherwise we get repeated strings */ + if (strcmp(string, "\n") != 0) { /* print human readable output - but skip empty lines */ fprintf(log_output, "%s%s", @@ -203,6 +206,18 @@ int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, cha if (debug_level > 3) debug_level = 3; + if (debug_level >= LOG_LVL_DEBUG && server_use_pipes == 1) + { + /* if we are enabling debug info then we need to write to a log file + * otherwise the pipe will get full and cause issues with gdb */ + FILE* file = fopen("openocd.log", "w"); + if (file) + { + log_output = file; + LOG_WARNING("enabling log output as we are using pipes"); + } + } + return ERROR_OK; } diff --git a/src/helper/options.c b/src/helper/options.c index cce77e5a..2ac9143e 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -24,10 +24,13 @@ #include "config.h" #endif +#include "replacements.h" + #include "types.h" #include "command.h" #include "configuration.h" #include "log.h" +#include "server.h" #include #include @@ -43,8 +46,9 @@ static struct option long_options[] = {"debug", optional_argument, 0, 'd'}, {"file", required_argument, 0, 'f'}, {"search", required_argument, 0, 's'}, - {"log_output", required_argument, 0, 'l'}, + {"log_output", required_argument, 0, 'l'}, {"command", required_argument, 0, 'c'}, + {"pipe", no_argument, 0, 'p'}, {0, 0, 0, 0} }; @@ -95,7 +99,7 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[] /* getopt_long stores the option index here. */ int option_index = 0; - c = getopt_long(argc, argv, "hvd::l:f:s:c:", long_options, &option_index); + c = getopt_long(argc, argv, "hvd::l:f:s:c:p", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) @@ -140,7 +144,20 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[] add_config_command(optarg); } break; - + case 'p': /* --pipe | -p */ +#if BUILD_ECOSBOARD == 1 + /* pipes unsupported on hosted platforms */ + LOG_WARNING("pipes not supported on this platform"); +#else +#ifdef IS_MINGW + /* pipes currently unsupported on win32 */ + LOG_WARNING("pipes currently unsupported on win32"); + exit(1); +#else + server_use_pipes = 1; +#endif +#endif + break; } } @@ -154,6 +171,7 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[] LOG_OUTPUT("--debug | -d\tset debug level <0-3>\n"); LOG_OUTPUT("--log_output | -l\tredirect log output to file \n"); LOG_OUTPUT("--command | -c\trun \n"); + LOG_OUTPUT("--pipe | -p\tuse pipes for gdb communication\n"); exit(-1); } @@ -161,7 +179,7 @@ int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[] { /* Nothing to do, version gets printed automatically. */ exit(-1); - } - + } + return ERROR_OK; } diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 06e24486..72f14095 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -169,10 +169,18 @@ int gdb_get_char(connection_t *connection, int* next_char) for (;;) { - retval=check_pending(connection, 1, NULL); - if (retval!=ERROR_OK) - return retval; - gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); + if (connection->service->type == CONNECTION_PIPE) + { + gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); + } + else + { + retval = check_pending(connection, 1, NULL); + if (retval != ERROR_OK) + return retval; + gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); + } + if (gdb_con->buf_cnt > 0) { break; @@ -268,10 +276,21 @@ int gdb_write(connection_t *connection, void *data, int len) gdb_connection_t *gdb_con = connection->priv; if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; - - if (write_socket(connection->fd, data, len) == len) + + if (connection->service->type == CONNECTION_PIPE) { - return ERROR_OK; + /* write to stdout */ + if (write(STDOUT_FILENO, data, len) == len) + { + return ERROR_OK; + } + } + else + { + if (write_socket(connection->fd, data, len) == len) + { + return ERROR_OK; + } } gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; @@ -2158,7 +2177,7 @@ int gdb_input(connection_t *connection) if (retval == ERROR_SERVER_REMOTE_CLOSED) return retval; - /* logging does not propagate the error, yet can set th gdb_con->closed flag */ + /* logging does not propagate the error, yet can set the gdb_con->closed flag */ if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; @@ -2177,34 +2196,37 @@ int gdb_init(void) return ERROR_OK; } - if (gdb_port == 0) + if (gdb_port == 0 && server_use_pipes == 0) { LOG_WARNING("no gdb port specified, using default port 3333"); gdb_port = 3333; } - while (target) + if (server_use_pipes) { - char service_name[8]; - - snprintf(service_name, 8, "gdb-%2.2i", target->target_number); - + /* only a single gdb connection when using a pipe */ + gdb_service = malloc(sizeof(gdb_service_t)); gdb_service->target = target; - add_service("gdb", CONNECTION_GDB, - gdb_port + target->target_number, - 1, gdb_new_connection, gdb_input, - gdb_connection_closed, - gdb_service); - - LOG_DEBUG("gdb service for target %s at port %i", - target->type->name, - gdb_port + target->target_number); + add_service("gdb", CONNECTION_PIPE, 0, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service); - target = target->next; + LOG_DEBUG("gdb service for target %s using pipes", target->type->name); } + else + { + while (target) + { + gdb_service = malloc(sizeof(gdb_service_t)); + gdb_service->target = target; + add_service("gdb", CONNECTION_TCP, gdb_port + target->target_number, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service); + + LOG_DEBUG("gdb service for target %s at port %i", target->type->name, gdb_port + target->target_number); + target = target->next; + } + } + return ERROR_OK; } diff --git a/src/server/server.c b/src/server/server.c index db61b1a5..b5b9a205 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -53,6 +53,9 @@ service_t *services = NULL; static int shutdown_openocd = 0; int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); +/* set when using pipes rather than tcp */ +int server_use_pipes = 0; + int add_connection(service_t *service, command_context_t *cmd_ctx) { unsigned int address_size; @@ -69,28 +72,44 @@ int add_connection(service_t *service, command_context_t *cmd_ctx) c->priv = NULL; c->next = NULL; - address_size = sizeof(c->sin); - - c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); - - /* This increases performance dramatically for e.g. GDB load which - * does not have a sliding window protocol. */ - retval=setsockopt(c->fd, /* socket affected */ - IPPROTO_TCP, /* set option at TCP level */ - TCP_NODELAY, /* name of option */ - (char *)&flag, /* the cast is historical cruft */ - sizeof(int)); /* length of option value */ - - LOG_INFO("accepting '%s' connection from %i", service->name, c->sin.sin_port); - if ((retval = service->new_connection(c)) == ERROR_OK) + if (service->type == CONNECTION_TCP) { + address_size = sizeof(c->sin); + + c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); + + /* This increases performance dramatically for e.g. GDB load which + * does not have a sliding window protocol. */ + retval=setsockopt(c->fd, /* socket affected */ + IPPROTO_TCP, /* set option at TCP level */ + TCP_NODELAY, /* name of option */ + (char *)&flag, /* the cast is historical cruft */ + sizeof(int)); /* length of option value */ + + LOG_INFO("accepting '%s' connection from %i", service->name, c->sin.sin_port); + if ((retval = service->new_connection(c)) != ERROR_OK) + { + close_socket(c->fd); + LOG_ERROR("attempted '%s' connection rejected", service->name); + free(c); + return retval; + } } - else + else if (service->type == CONNECTION_PIPE) { - close_socket(c->fd); - LOG_ERROR("attempted '%s' connection rejected", service->name); - free(c); - return retval; +#ifndef _WIN32 + c->fd = service->fd; + + /* do not check for new connections again on stdin */ + service->fd = -1; +#endif + LOG_INFO("accepting '%s' connection from pipe", service->name); + if ((retval = service->new_connection(c)) != ERROR_OK) + { + LOG_ERROR("attempted '%s' connection rejected", service->name); + free(c); + return retval; + } } /* add to the end of linked list */ @@ -113,7 +132,8 @@ int remove_connection(service_t *service, connection_t *connection) if (c->fd == connection->fd) { service->connection_closed(c); - close_socket(c->fd); + if (service->type == CONNECTION_TCP) + close_socket(c->fd); command_done(c->cmd_ctx); /* delete connection */ @@ -150,44 +170,67 @@ int add_service(char *name, enum connection_type type, unsigned short port, int c->priv = priv; c->next = NULL; - if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) - { - LOG_ERROR("error creating socket: %s", strerror(errno)); - exit(-1); - } - - setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int)); - - socket_nonblock(c->fd); - - memset(&c->sin, 0, sizeof(c->sin)); - c->sin.sin_family = AF_INET; - c->sin.sin_addr.s_addr = INADDR_ANY; - c->sin.sin_port = htons(port); - - if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) + if (type == CONNECTION_TCP) { - LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); - exit(-1); - } - + if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + LOG_ERROR("error creating socket: %s", strerror(errno)); + exit(-1); + } + + setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int)); + + socket_nonblock(c->fd); + + memset(&c->sin, 0, sizeof(c->sin)); + c->sin.sin_family = AF_INET; + c->sin.sin_addr.s_addr = INADDR_ANY; + c->sin.sin_port = htons(port); + + if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) + { + LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); + exit(-1); + } + #ifndef _WIN32 - int segsize=65536; - setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int)); + int segsize=65536; + setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int)); #endif - int window_size = 128 * 1024; - - /* These setsockopt()s must happen before the listen() */ - - setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF, - (char *)&window_size, sizeof(window_size)); - setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF, - (char *)&window_size, sizeof(window_size)); + int window_size = 128 * 1024; - if (listen(c->fd, 1) == -1) + /* These setsockopt()s must happen before the listen() */ + + setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF, + (char *)&window_size, sizeof(window_size)); + setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF, + (char *)&window_size, sizeof(window_size)); + + if (listen(c->fd, 1) == -1) + { + LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); + exit(-1); + } + } + else if (type == CONNECTION_PIPE) { - LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); - exit(-1); + /* use stdin */ + c->fd = STDIN_FILENO; + +#ifdef _WIN32 + /* for win32 set stdin/stdout to binary mode */ + if (_setmode(_fileno(stdout), _O_BINARY) < 0) + LOG_WARNING("cannot change stdout mode to binary"); + if (_setmode(_fileno(stdin), _O_BINARY) < 0) + LOG_WARNING("cannot change stdin mode to binary"); +#else + socket_nonblock(c->fd); +#endif + } + else + { + LOG_ERROR("unknown connection type: %d", type); + exit(1); } /* add to the end of linked list */ @@ -310,14 +353,18 @@ int server_loop(command_context_t *command_context) #ifndef _WIN32 #if BUILD_ECOSBOARD == 0 - /* add STDIN to read_fds */ - FD_SET(fileno(stdin), &read_fds); + if (server_use_pipes == 0) + { + /* add STDIN to read_fds */ + FD_SET(fileno(stdin), &read_fds); + } #endif #endif openocd_sleep_prelude(); kept_alive(); - // Only while we're sleeping we'll let others run + + /* Only while we're sleeping we'll let others run */ retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv); openocd_sleep_postlude(); @@ -371,11 +418,14 @@ int server_loop(command_context_t *command_context) } else { - struct sockaddr_in sin; - unsigned int address_size = sizeof(sin); - int tmp_fd; - tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); - close_socket(tmp_fd); + if (service->type != CONNECTION_PIPE) + { + struct sockaddr_in sin; + unsigned int address_size = sizeof(sin); + int tmp_fd; + tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); + close_socket(tmp_fd); + } LOG_INFO("rejected '%s' connection, no more connections allowed", service->name); } } @@ -389,11 +439,16 @@ int server_loop(command_context_t *command_context) { if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) { - if (service->input(c) != ERROR_OK) + if ((retval = service->input(c)) != ERROR_OK) { connection_t *next = c->next; + if (service->type == CONNECTION_PIPE) + { + /* if connection uses a pipe then shutdown openocd on error */ + shutdown_openocd = 1; + } remove_connection(service, c); - LOG_INFO("dropped '%s' connection", service->name); + LOG_INFO("dropped '%s' connection - error %d", service->name, retval); c = next; continue; } @@ -405,11 +460,15 @@ int server_loop(command_context_t *command_context) #ifndef _WIN32 #if BUILD_ECOSBOARD == 0 - if (FD_ISSET(fileno(stdin), &read_fds)) + /* check for data on stdin if not using pipes */ + if (server_use_pipes == 0) { - if (getc(stdin) == 'x') + if (FD_ISSET(fileno(stdin), &read_fds)) { - shutdown_openocd = 1; + if (getc(stdin) == 'x') + { + shutdown_openocd = 1; + } } } #endif @@ -459,7 +518,6 @@ int server_init(void) signal(SIGBREAK, sig_handler); signal(SIGABRT, sig_handler); #endif - return ERROR_OK; } diff --git a/src/server/server.h b/src/server/server.h index fd1abbf5..451ac6f7 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -34,9 +34,8 @@ enum connection_type { - CONNECTION_GDB, - CONNECTION_TELNET, - CONNECTION_TCL, + CONNECTION_TCP, + CONNECTION_PIPE }; typedef struct connection_s @@ -76,6 +75,8 @@ extern int server_quit(void); extern int server_loop(command_context_t *command_context); extern int server_register_commands(command_context_t *context); +extern int server_use_pipes; + #define ERROR_SERVER_REMOTE_CLOSED (-400) #define ERROR_CONNECTION_REJECTED (-401) diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index a6601ffd..edc209bc 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -179,7 +179,7 @@ int tcl_init(void) tcl_port = 6666; } - retval = add_service("tcl", CONNECTION_TCL, tcl_port, 1, tcl_new_connection, tcl_input, tcl_closed, NULL); + retval = add_service("tcl", CONNECTION_TCP, tcl_port, 1, tcl_new_connection, tcl_input, tcl_closed, NULL); return retval; } diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 1209b7a9..dc555214 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -615,7 +615,7 @@ int telnet_init(char *banner) telnet_service->banner = banner; - add_service("telnet", CONNECTION_TELNET, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service); + add_service("telnet", CONNECTION_TCP, telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service); return ERROR_OK; } diff --git a/src/target/target.c b/src/target/target.c index 3d0f8e27..f86d8f39 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -232,7 +232,6 @@ const Jim_Nvp nvp_target_debug_reason [] = { { .name = NULL, .value = -1 }, }; - const Jim_Nvp nvp_target_endian[] = { { .name = "big", .value = TARGET_BIG_ENDIAN }, { .name = "little", .value = TARGET_LITTLE_ENDIAN }, @@ -249,8 +248,7 @@ const Jim_Nvp nvp_reset_modes[] = { { .name = NULL , .value = -1 }, }; -static int -max_target_number( void ) +static int max_target_number(void) { target_t *t; int x; @@ -267,8 +265,7 @@ max_target_number( void ) } /* determine the number of the new target */ -static int -new_target_number( void ) +static int new_target_number(void) { target_t *t; int x; -- cgit v1.2.3