- 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
__archive__
ntfreak 2008-12-15 09:43:26 +00:00
parent 459d03e3bb
commit 47d0449347
10 changed files with 272 additions and 146 deletions

View File

@ -15,7 +15,7 @@
@itemize @bullet @itemize @bullet
@item Copyright @copyright{} 2008 The OpenOCD Project @item Copyright @copyright{} 2008 The OpenOCD Project
@item Copyright @copyright{} 2007-2008 Spen @email{spen@@spen-soft.co.uk} @item Copyright @copyright{} 2007-2008 Spencer Oliver @email{spen@@spen-soft.co.uk}
@item Copyright @copyright{} 2008 Oyvind Harboe @email{oyvind.harboe@@zylin.com} @item Copyright @copyright{} 2008 Oyvind Harboe @email{oyvind.harboe@@zylin.com}
@item Copyright @copyright{} 2008 Duane Ellis @email{openocd@@duaneellis.com} @item Copyright @copyright{} 2008 Duane Ellis @email{openocd@@duaneellis.com}
@end itemize @end itemize
@ -411,9 +411,10 @@ bash$ openocd --help
--debug | -d set debug level <0-3> --debug | -d set debug level <0-3>
--log_output | -l redirect log output to file <name> --log_output | -l redirect log output to file <name>
--command | -c run <command> --command | -c run <command>
--pipe | -p use pipes when talking to gdb
@end verbatim @end verbatim
By default openocd reads the file configuration file ``openocd.cfg'' By default OpenOCD reads the file configuration file ``openocd.cfg''
in the current directory. To specify a different (or multiple) in the current directory. To specify a different (or multiple)
configuration file, you can use the ``-f'' option. For example: configuration file, you can use the ``-f'' option. For example:
@ -445,6 +446,9 @@ Search paths for config/script files can be added to OpenOCD by using
the @option{-s <search>} switch. The current directory and the OpenOCD the @option{-s <search>} switch. The current directory and the OpenOCD
target library is in the search path by default. target library is in the search path by default.
For details on the @option{-p} option. @xref{Connecting to GDB}.
Option @option{-p} is not currently supported under native win32.
Note! OpenOCD will launch the GDB & telnet server even if it can not Note! OpenOCD will launch the GDB & telnet server even if it can not
establish a connection with the target. In general, it is possible for establish a connection with the target. In general, it is possible for
the JTAG controller to be unresponsive until the target is set up the JTAG controller to be unresponsive until the target is set up
@ -455,7 +459,7 @@ correctly via e.g. GDB monitor commands in a GDB init script.
@cindex configuration @cindex configuration
@section Outline @section Outline
There are 4 basic ways of ``configurating'' openocd to run, they are: There are 4 basic ways of ``configurating'' OpenOCD to run, they are:
@enumerate @enumerate
@item A small openocd.cfg file which ``sources'' other configuration files @item A small openocd.cfg file which ``sources'' other configuration files
@ -671,7 +675,7 @@ tap identifier dotted name.
every chip. If the @t{-expected-id} is nonzero, OpenOCD attempts every chip. If the @t{-expected-id} is nonzero, OpenOCD attempts
to verify the tap id number verses configuration file and may issue an to verify the tap id number verses configuration file and may issue an
error or warning like this. The hope is this will help pin point error or warning like this. The hope is this will help pin point
problem openocd configurations. problem OpenOCD configurations.
@example @example
Info: JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3) Info: JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
@ -904,7 +908,7 @@ command interpretor today (28/nov/2008) is a mixture of (newer)
JIM-Tcl commands, and (older) the orginal command interpretor. JIM-Tcl commands, and (older) the orginal command interpretor.
@item @b{Commands} @item @b{Commands}
@* At the openocd telnet command line (or via the GDB mon command) one @* At the OpenOCD telnet command line (or via the GDB mon command) one
can type a Tcl for() loop, set variables, etc. can type a Tcl for() loop, set variables, etc.
@item @b{Historical Note} @item @b{Historical Note}
@ -1145,7 +1149,7 @@ if compiled with FTD2XX support.
@b{TODO:} Confirm the following: On windows the name needs to end with @b{TODO:} Confirm the following: On windows the name needs to end with
a ``space A''? Or not? It has to do with the FTD2xx driver. When must a ``space A''? Or not? It has to do with the FTD2xx driver. When must
this be added and when must it not be added? Why can't the code in the this be added and when must it not be added? Why can't the code in the
interface or in openocd automatically add this if needed? -- Duane. interface or in OpenOCD automatically add this if needed? -- Duane.
@item @b{ft2232_serial} <@var{serial-number}> @item @b{ft2232_serial} <@var{serial-number}>
@cindex ft2232_serial @cindex ft2232_serial
@ -1527,7 +1531,7 @@ then ``bypass'' the tap, the tap is completely removed from the
circuit and skipped. circuit and skipped.
From OpenOCDs view point, a JTAG TAP is in one of 3 states: From OpenOCD's view point, a JTAG TAP is in one of 3 states:
@itemize @bullet @itemize @bullet
@item @b{Enabled - Not In ByPass} and has a variable bit length @item @b{Enabled - Not In ByPass} and has a variable bit length
@ -1640,7 +1644,7 @@ configure it like this:
puts [format "The button is %s" $x] puts [format "The button is %s" $x]
@end example @end example
In OpenOCDs terms, the ``target'' is an object just like a Tcl/Tk In OpenOCD's terms, the ``target'' is an object just like a Tcl/Tk
button. Commands avaialble as a ``target object'' are: button. Commands avaialble as a ``target object'' are:
@comment START targetobj commands. @comment START targetobj commands.
@ -1841,7 +1845,7 @@ via the configure option or to query the target via cget.
@item @b{-work-area-size [ADDRESS]} specify/set the work area @item @b{-work-area-size [ADDRESS]} specify/set the work area
@item @b{-work-area-backup [0|1]} does the work area get backed up @item @b{-work-area-backup [0|1]} does the work area get backed up
@item @b{-endian [big|little]} @item @b{-endian [big|little]}
@item @b{-variant [NAME]} some chips have varients openocd needs to know about @item @b{-variant [NAME]} some chips have varients OpenOCD needs to know about
@item @b{-chain-position DOTTED.NAME} the tap name this target refers to. @item @b{-chain-position DOTTED.NAME} the tap name this target refers to.
@end itemize @end itemize
Example: Example:
@ -1870,7 +1874,7 @@ cores.
@* None (this is also used as the ARM946) @* None (this is also used as the ARM946)
@item @b{cortex_m3} @item @b{cortex_m3}
@* use variant <@var{-variant lm3s}> when debugging luminary lm3s targets. This will cause @* use variant <@var{-variant lm3s}> when debugging luminary lm3s targets. This will cause
openocd to use a software reset rather than asserting SRST to avoid a issue with clearing OpenOCD to use a software reset rather than asserting SRST to avoid a issue with clearing
the debug registers. This is fixed in Fury Rev B, DustDevil Rev B, Tempest, these revisions will the debug registers. This is fixed in Fury Rev B, DustDevil Rev B, Tempest, these revisions will
be detected and the normal reset behaviour used. be detected and the normal reset behaviour used.
@item @b{xscale} @item @b{xscale}
@ -1880,9 +1884,9 @@ be detected and the normal reset behaviour used.
@item @b{mips_m4k} @item @b{mips_m4k}
@* Use variant @option{ejtag_srst} when debugging targets that do not @* Use variant @option{ejtag_srst} when debugging targets that do not
provide a functional SRST line on the EJTAG connector. This causes provide a functional SRST line on the EJTAG connector. This causes
openocd to instead use an EJTAG software reset command to reset the OpenOCD to instead use an EJTAG software reset command to reset the
processor. You still need to enable @option{srst} on the reset processor. You still need to enable @option{srst} on the reset
configuration command to enable openocd hardware reset functionality. configuration command to enable OpenOCD hardware reset functionality.
@comment END varients @comment END varients
@end itemize @end itemize
@section working_area - Command Removed @section working_area - Command Removed
@ -2004,7 +2008,7 @@ to a <@var{file}>.
@end itemize @end itemize
@section flash bank command @section flash bank command
The @b{flash bank} command is used to configure one or more flash chips (or banks in openocd terms) The @b{flash bank} command is used to configure one or more flash chips (or banks in OpenOCD terms)
@example @example
@b{flash bank} <@var{driver}> <@var{base}> <@var{size}> <@var{chip_width}> @b{flash bank} <@var{driver}> <@var{base}> <@var{size}> <@var{chip_width}>
@ -2170,7 +2174,7 @@ erase the device.
@end itemize @end itemize
Note: Before using the str9xpec driver here is some background info to help Note: Before using the str9xpec driver here is some background info to help
you better understand how the drivers works. Openocd has two flash drivers for you better understand how the drivers works. OpenOCD has two flash drivers for
the str9. the str9.
@enumerate @enumerate
@item @item
@ -2793,41 +2797,52 @@ openocd -f interface/parport.cfg -f target/at91r40008.cfg -c init -c reset
OpenOCD complies with the remote gdbserver protocol, and as such can be used OpenOCD complies with the remote gdbserver protocol, and as such can be used
to debug remote targets. to debug remote targets.
@section Connecting to gdb @section Connecting to GDB
@cindex Connecting to gdb @cindex Connecting to GDB
@anchor{Connecting to GDB}
Use GDB 6.7 or newer with OpenOCD if you run into trouble. For Use GDB 6.7 or newer with OpenOCD if you run into trouble. For
instance 6.3 has a known bug where it produces bogus memory access instance 6.3 has a known bug where it produces bogus memory access
errors, which has since been fixed: look up 1836 in errors, which has since been fixed: look up 1836 in
@url{http://sourceware.org/cgi-bin/gnatsweb.pl?database=gdb} @url{http://sourceware.org/cgi-bin/gnatsweb.pl?database=gdb}
@*OpenOCD can communicate with GDB in two ways:
A connection is typically started as follows: @enumerate
@item
A socket (tcp) connection is typically started as follows:
@example @example
target remote localhost:3333 target remote localhost:3333
@end example @end example
This would cause gdb to connect to the gdbserver on the local pc using port 3333. This would cause GDB to connect to the gdbserver on the local pc using port 3333.
@item
A pipe connection is typically started as follows:
@example
target remote openocd --pipe
@end example
This would cause GDB to run OpenOCD and communicate using pipes (stdin/stdout).
Using this method has the advantage of GDB starting/stopping OpenOCD for debug session.
@end enumerate
To see a list of available OpenOCD commands type @option{monitor help} on the @*To see a list of available OpenOCD commands type @option{monitor help} on the
gdb commandline. GDB commandline.
OpenOCD supports the gdb @option{qSupported} packet, this enables information OpenOCD supports the gdb @option{qSupported} packet, this enables information
to be sent by the gdb server (openocd) to gdb. Typical information includes to be sent by the gdb server (OpenOCD) to GDB. Typical information includes
packet size and device memory map. packet size and device memory map.
Previous versions of OpenOCD required the following gdb options to increase Previous versions of OpenOCD required the following GDB options to increase
the packet size and speed up gdb communication. the packet size and speed up GDB communication.
@example @example
set remote memory-write-packet-size 1024 set remote memory-write-packet-size 1024
set remote memory-write-packet-size fixed set remote memory-write-packet-size fixed
set remote memory-read-packet-size 1024 set remote memory-read-packet-size 1024
set remote memory-read-packet-size fixed set remote memory-read-packet-size fixed
@end example @end example
This is now handled in the @option{qSupported} PacketSize. This is now handled in the @option{qSupported} PacketSize and should not be required.
@section Programming using gdb @section Programming using GDB
@cindex Programming using gdb @cindex Programming using GDB
By default the target memory map is sent to gdb, this can be disabled by By default the target memory map is sent to GDB, this can be disabled by
the following OpenOCD config option: the following OpenOCD config option:
@example @example
gdb_memory_map disable gdb_memory_map disable
@ -2836,34 +2851,34 @@ For this to function correctly a valid flash config must also be configured
in OpenOCD. For faster performance you should also configure a valid in OpenOCD. For faster performance you should also configure a valid
working area. working area.
Informing gdb of the memory map of the target will enable gdb to protect any Informing GDB of the memory map of the target will enable GDB to protect any
flash area of the target and use hardware breakpoints by default. This means flash area of the target and use hardware breakpoints by default. This means
that the OpenOCD option @option{gdb_breakpoint_override} is not required when that the OpenOCD option @option{gdb_breakpoint_override} is not required when
using a memory map. @xref{gdb_breakpoint_override}. using a memory map. @xref{gdb_breakpoint_override}.
To view the configured memory map in gdb, use the gdb command @option{info mem} To view the configured memory map in GDB, use the gdb command @option{info mem}
All other unasigned addresses within gdb are treated as RAM. All other unasigned addresses within GDB are treated as RAM.
GDB 6.8 and higher set any memory area not in the memory map as inaccessible, GDB 6.8 and higher set any memory area not in the memory map as inaccessible,
this can be changed to the old behaviour by using the following gdb command. this can be changed to the old behaviour by using the following GDB command.
@example @example
set mem inaccessible-by-default off set mem inaccessible-by-default off
@end example @end example
If @option{gdb_flash_program enable} is also used, gdb will be able to If @option{gdb_flash_program enable} is also used, GDB will be able to
program any flash memory using the vFlash interface. program any flash memory using the vFlash interface.
gdb will look at the target memory map when a load command is given, if any GDB will look at the target memory map when a load command is given, if any
areas to be programmed lie within the target flash area the vFlash packets areas to be programmed lie within the target flash area the vFlash packets
will be used. will be used.
If the target needs configuring before gdb programming, an event If the target needs configuring before GDB programming, an event
script can be executed. script can be executed.
@example @example
$_TARGETNAME configure -event EVENTNAME BODY $_TARGETNAME configure -event EVENTNAME BODY
@end example @end example
To verify any flash programming the gdb command @option{compare-sections} To verify any flash programming the GDB command @option{compare-sections}
can be used. can be used.
@node TCL scripting API @node TCL scripting API
@ -3598,7 +3613,7 @@ foreach who @{A B C D E@}
OpenOCD comes with a target configuration script library. These scripts can be OpenOCD comes with a target configuration script library. These scripts can be
used as-is or serve as a starting point. used as-is or serve as a starting point.
The target library is published together with the openocd executable and The target library is published together with the OpenOCD executable and
the path to the target library is in the OpenOCD script search path. the path to the target library is in the OpenOCD script search path.
Similarly there are example scripts for configuring the JTAG interface. Similarly there are example scripts for configuring the JTAG interface.

View File

@ -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 METASOURCES = AUTO
AM_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" -DPKGLIBDIR=\"$(pkglibdir)\" @CPPFLAGS@ AM_CPPFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" -DPKGLIBDIR=\"$(pkglibdir)\" @CPPFLAGS@
noinst_LIBRARIES = libhelper.a noinst_LIBRARIES = libhelper.a

View File

@ -31,6 +31,7 @@
#include "configuration.h" #include "configuration.h"
#include "time_support.h" #include "time_support.h"
#include "command.h" #include "command.h"
#include "server.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -108,9 +109,11 @@ static void log_puts(enum log_levels level, const char *file, int line, const ch
#endif #endif
string); 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 */ /* print human readable output - but skip empty lines */
fprintf(log_output, "%s%s", 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) if (debug_level > 3)
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; return ERROR_OK;
} }

View File

@ -24,10 +24,13 @@
#include "config.h" #include "config.h"
#endif #endif
#include "replacements.h"
#include "types.h" #include "types.h"
#include "command.h" #include "command.h"
#include "configuration.h" #include "configuration.h"
#include "log.h" #include "log.h"
#include "server.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -43,8 +46,9 @@ static struct option long_options[] =
{"debug", optional_argument, 0, 'd'}, {"debug", optional_argument, 0, 'd'},
{"file", required_argument, 0, 'f'}, {"file", required_argument, 0, 'f'},
{"search", required_argument, 0, 's'}, {"search", required_argument, 0, 's'},
{"log_output", required_argument, 0, 'l'}, {"log_output", required_argument, 0, 'l'},
{"command", required_argument, 0, 'c'}, {"command", required_argument, 0, 'c'},
{"pipe", no_argument, 0, 'p'},
{0, 0, 0, 0} {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. */ /* getopt_long stores the option index here. */
int option_index = 0; 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. */ /* Detect the end of the options. */
if (c == -1) 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); add_config_command(optarg);
} }
break; 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("--debug | -d\tset debug level <0-3>\n");
LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n"); LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n");
LOG_OUTPUT("--command | -c\trun <command>\n"); LOG_OUTPUT("--command | -c\trun <command>\n");
LOG_OUTPUT("--pipe | -p\tuse pipes for gdb communication\n");
exit(-1); 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. */ /* Nothing to do, version gets printed automatically. */
exit(-1); exit(-1);
} }
return ERROR_OK; return ERROR_OK;
} }

View File

@ -169,10 +169,18 @@ int gdb_get_char(connection_t *connection, int* next_char)
for (;;) for (;;)
{ {
retval=check_pending(connection, 1, NULL); if (connection->service->type == CONNECTION_PIPE)
if (retval!=ERROR_OK) {
return retval; gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE);
gdb_con->buf_cnt = read_socket(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) if (gdb_con->buf_cnt > 0)
{ {
break; break;
@ -268,10 +276,21 @@ int gdb_write(connection_t *connection, void *data, int len)
gdb_connection_t *gdb_con = connection->priv; gdb_connection_t *gdb_con = connection->priv;
if (gdb_con->closed) if (gdb_con->closed)
return ERROR_SERVER_REMOTE_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; gdb_con->closed = 1;
return ERROR_SERVER_REMOTE_CLOSED; return ERROR_SERVER_REMOTE_CLOSED;
@ -2158,7 +2177,7 @@ int gdb_input(connection_t *connection)
if (retval == ERROR_SERVER_REMOTE_CLOSED) if (retval == ERROR_SERVER_REMOTE_CLOSED)
return retval; 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) if (gdb_con->closed)
return ERROR_SERVER_REMOTE_CLOSED; return ERROR_SERVER_REMOTE_CLOSED;
@ -2177,34 +2196,37 @@ int gdb_init(void)
return ERROR_OK; 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"); LOG_WARNING("no gdb port specified, using default port 3333");
gdb_port = 3333; gdb_port = 3333;
} }
while (target) if (server_use_pipes)
{ {
char service_name[8]; /* only a single gdb connection when using a pipe */
snprintf(service_name, 8, "gdb-%2.2i", target->target_number);
gdb_service = malloc(sizeof(gdb_service_t)); gdb_service = malloc(sizeof(gdb_service_t));
gdb_service->target = target; gdb_service->target = target;
add_service("gdb", CONNECTION_GDB, add_service("gdb", CONNECTION_PIPE, 0, 1, gdb_new_connection, gdb_input, gdb_connection_closed, gdb_service);
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", LOG_DEBUG("gdb service for target %s using pipes", target->type->name);
target->type->name,
gdb_port + target->target_number);
target = target->next;
} }
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; return ERROR_OK;
} }

View File

@ -53,6 +53,9 @@ service_t *services = NULL;
static int shutdown_openocd = 0; static int shutdown_openocd = 0;
int handle_shutdown_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); 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) int add_connection(service_t *service, command_context_t *cmd_ctx)
{ {
unsigned int address_size; unsigned int address_size;
@ -69,28 +72,44 @@ int add_connection(service_t *service, command_context_t *cmd_ctx)
c->priv = NULL; c->priv = NULL;
c->next = NULL; c->next = NULL;
address_size = sizeof(c->sin); if (service->type == CONNECTION_TCP)
{
c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); address_size = sizeof(c->sin);
/* 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); c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size);
if ((retval = service->new_connection(c)) == ERROR_OK)
{ /* 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); #ifndef _WIN32
LOG_ERROR("attempted '%s' connection rejected", service->name); c->fd = service->fd;
free(c);
return retval; /* 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 */ /* 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) if (c->fd == connection->fd)
{ {
service->connection_closed(c); service->connection_closed(c);
close_socket(c->fd); if (service->type == CONNECTION_TCP)
close_socket(c->fd);
command_done(c->cmd_ctx); command_done(c->cmd_ctx);
/* delete connection */ /* delete connection */
@ -150,44 +170,67 @@ int add_service(char *name, enum connection_type type, unsigned short port, int
c->priv = priv; c->priv = priv;
c->next = NULL; c->next = NULL;
if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) if (type == CONNECTION_TCP)
{ {
LOG_ERROR("error creating socket: %s", strerror(errno)); if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
exit(-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); setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void*)&so_reuseaddr_option, sizeof(int));
memset(&c->sin, 0, sizeof(c->sin)); socket_nonblock(c->fd);
c->sin.sin_family = AF_INET;
c->sin.sin_addr.s_addr = INADDR_ANY; memset(&c->sin, 0, sizeof(c->sin));
c->sin.sin_port = htons(port); c->sin.sin_family = AF_INET;
c->sin.sin_addr.s_addr = INADDR_ANY;
if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) c->sin.sin_port = htons(port);
{
LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1)
exit(-1); {
} LOG_ERROR("couldn't bind to socket: %s", strerror(errno));
exit(-1);
}
#ifndef _WIN32 #ifndef _WIN32
int segsize=65536; int segsize=65536;
setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int)); setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int));
#endif #endif
int window_size = 128 * 1024; int window_size = 128 * 1024;
/* These setsockopt()s must happen before the listen() */
setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF, /* These setsockopt()s must happen before the listen() */
(char *)&window_size, sizeof(window_size));
setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF, setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF,
(char *)&window_size, sizeof(window_size)); (char *)&window_size, sizeof(window_size));
setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF,
if (listen(c->fd, 1) == -1) (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)); /* use stdin */
exit(-1); 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 */ /* add to the end of linked list */
@ -310,14 +353,18 @@ int server_loop(command_context_t *command_context)
#ifndef _WIN32 #ifndef _WIN32
#if BUILD_ECOSBOARD == 0 #if BUILD_ECOSBOARD == 0
/* add STDIN to read_fds */ if (server_use_pipes == 0)
FD_SET(fileno(stdin), &read_fds); {
/* add STDIN to read_fds */
FD_SET(fileno(stdin), &read_fds);
}
#endif #endif
#endif #endif
openocd_sleep_prelude(); openocd_sleep_prelude();
kept_alive(); 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); retval = select(fd_max + 1, &read_fds, NULL, NULL, &tv);
openocd_sleep_postlude(); openocd_sleep_postlude();
@ -371,11 +418,14 @@ int server_loop(command_context_t *command_context)
} }
else else
{ {
struct sockaddr_in sin; if (service->type != CONNECTION_PIPE)
unsigned int address_size = sizeof(sin); {
int tmp_fd; struct sockaddr_in sin;
tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); unsigned int address_size = sizeof(sin);
close_socket(tmp_fd); 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); 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 ((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; 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); remove_connection(service, c);
LOG_INFO("dropped '%s' connection", service->name); LOG_INFO("dropped '%s' connection - error %d", service->name, retval);
c = next; c = next;
continue; continue;
} }
@ -405,11 +460,15 @@ int server_loop(command_context_t *command_context)
#ifndef _WIN32 #ifndef _WIN32
#if BUILD_ECOSBOARD == 0 #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 #endif
@ -459,7 +518,6 @@ int server_init(void)
signal(SIGBREAK, sig_handler); signal(SIGBREAK, sig_handler);
signal(SIGABRT, sig_handler); signal(SIGABRT, sig_handler);
#endif #endif
return ERROR_OK; return ERROR_OK;
} }

View File

@ -34,9 +34,8 @@
enum connection_type enum connection_type
{ {
CONNECTION_GDB, CONNECTION_TCP,
CONNECTION_TELNET, CONNECTION_PIPE
CONNECTION_TCL,
}; };
typedef struct connection_s 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_loop(command_context_t *command_context);
extern int server_register_commands(command_context_t *context); extern int server_register_commands(command_context_t *context);
extern int server_use_pipes;
#define ERROR_SERVER_REMOTE_CLOSED (-400) #define ERROR_SERVER_REMOTE_CLOSED (-400)
#define ERROR_CONNECTION_REJECTED (-401) #define ERROR_CONNECTION_REJECTED (-401)

View File

@ -179,7 +179,7 @@ int tcl_init(void)
tcl_port = 6666; 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; return retval;
} }

View File

@ -615,7 +615,7 @@ int telnet_init(char *banner)
telnet_service->banner = 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; return ERROR_OK;
} }

View File

@ -232,7 +232,6 @@ const Jim_Nvp nvp_target_debug_reason [] = {
{ .name = NULL, .value = -1 }, { .name = NULL, .value = -1 },
}; };
const Jim_Nvp nvp_target_endian[] = { const Jim_Nvp nvp_target_endian[] = {
{ .name = "big", .value = TARGET_BIG_ENDIAN }, { .name = "big", .value = TARGET_BIG_ENDIAN },
{ .name = "little", .value = TARGET_LITTLE_ENDIAN }, { .name = "little", .value = TARGET_LITTLE_ENDIAN },
@ -249,8 +248,7 @@ const Jim_Nvp nvp_reset_modes[] = {
{ .name = NULL , .value = -1 }, { .name = NULL , .value = -1 },
}; };
static int static int max_target_number(void)
max_target_number( void )
{ {
target_t *t; target_t *t;
int x; int x;
@ -267,8 +265,7 @@ max_target_number( void )
} }
/* determine the number of the new target */ /* determine the number of the new target */
static int static int new_target_number(void)
new_target_number( void )
{ {
target_t *t; target_t *t;
int x; int x;