* NEWS: Add entry for stdio gdbserver.
gdbserver/ * linux-low.c (linux_create_inferior): If stdio connection, redirect stdin from /dev/null, stdout to stderr. * remote-utils.c (remote_is_stdio): New static global. (remote_connection_is_stdio): New function. (remote_prepare): Handle stdio connection. (remote_open): Ditto. (remote_close): Don't close stdin for stdio connections. (read_prim,write_prim): New functions. Replace all calls to read/write to these. * server.c (main): Watch for "-" argument. Move call to remote_prepare before start_inferior. * server.h (STDIO_CONNECTION_NAME): New macro. (remote_connection_is_stdio): Declare. doc/ * gdb.texinfo (Server): Document -/stdio argument to gdbserver. testsuite/ * lib/gdbserver-support.exp (gdb_target_cmd): Recognize stdio gdbserver output. (gdbserver_default_get_remote_address): New function. (gdbserver_start): Call gdb,get_remote_address to compute argument to "target remote" command.
This commit is contained in:
parent
e77616d77a
commit
e0f9f06220
@ -1,3 +1,7 @@
|
||||
2011-12-16 Doug Evans <dje@google.com>
|
||||
|
||||
* NEWS: Add entry for stdio gdbserver.
|
||||
|
||||
2011-12-16 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* python/python.c: Define python_excp_enums.
|
||||
|
3
gdb/NEWS
3
gdb/NEWS
@ -3,6 +3,9 @@
|
||||
|
||||
*** Changes since GDB 7.4
|
||||
|
||||
* GDBserver now supports stdio connections.
|
||||
E.g. (gdb) target remote | ssh myhost gdbserver - hello
|
||||
|
||||
*** Changes in GDB 7.4
|
||||
|
||||
* GDB now handles ambiguous linespecs more consistently; the existing
|
||||
|
@ -1,3 +1,7 @@
|
||||
2011-12-16 Doug Evans <dje@google.com>
|
||||
|
||||
* gdb.texinfo (Server): Document -/stdio argument to gdbserver.
|
||||
|
||||
2011-12-16 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* gdb.texinfo (Python Commands): Remove "maint set/show print
|
||||
|
@ -16766,8 +16766,10 @@ syntax is:
|
||||
target> gdbserver @var{comm} @var{program} [ @var{args} @dots{} ]
|
||||
@end smallexample
|
||||
|
||||
@var{comm} is either a device name (to use a serial line) or a TCP
|
||||
hostname and portnumber. For example, to debug Emacs with the argument
|
||||
@var{comm} is either a device name (to use a serial line), or a TCP
|
||||
hostname and portnumber, or @code{-} or @code{stdio} to use
|
||||
stdin/stdout of @code{gdbserver}.
|
||||
For example, to debug Emacs with the argument
|
||||
@samp{foo.txt} and communicate with @value{GDBN} over the serial port
|
||||
@file{/dev/com1}:
|
||||
|
||||
@ -16796,6 +16798,23 @@ conflicts with another service, @code{gdbserver} prints an error message
|
||||
and exits.} You must use the same port number with the host @value{GDBN}
|
||||
@code{target remote} command.
|
||||
|
||||
The @code{stdio} connection is useful when starting @code{gdbserver}
|
||||
with ssh:
|
||||
|
||||
@smallexample
|
||||
(gdb) target remote | ssh -T hostname gdbserver - hello
|
||||
@end smallexample
|
||||
|
||||
The @samp{-T} option to ssh is provided because we don't need a remote pty,
|
||||
and we don't want escape-character handling. Ssh does this by default when
|
||||
a command is provided, the flag is provided to make it explicit.
|
||||
You could elide it if you want to.
|
||||
|
||||
Programs started with stdio-connected gdbserver have @file{/dev/null} for
|
||||
@code{stdin}, and @code{stdout},@code{stderr} are sent back to gdb for
|
||||
display through a pipe connected to gdbserver.
|
||||
Both @code{stdout} and @code{stderr} use the same pipe.
|
||||
|
||||
@subsubsection Attaching to a Running Program
|
||||
@cindex attach to a program, @code{gdbserver}
|
||||
@cindex @option{--attach}, @code{gdbserver} option
|
||||
|
@ -569,6 +569,18 @@ linux_create_inferior (char *program, char **allargs)
|
||||
|
||||
setpgid (0, 0);
|
||||
|
||||
/* If gdbserver is connected to gdb via stdio, redirect the inferior's
|
||||
stdout to stderr so that inferior i/o doesn't corrupt the connection.
|
||||
Also, redirect stdin to /dev/null. */
|
||||
if (remote_connection_is_stdio ())
|
||||
{
|
||||
close (0);
|
||||
open ("/dev/null", O_RDONLY);
|
||||
dup2 (2, 1);
|
||||
write (2, "stdin/stdout redirected\n",
|
||||
sizeof ("stdin/stdout redirected\n") - 1);
|
||||
}
|
||||
|
||||
execv (program, allargs);
|
||||
if (errno == ENOENT)
|
||||
execvp (program, allargs);
|
||||
|
@ -107,6 +107,8 @@ struct sym_cache
|
||||
int remote_debug = 0;
|
||||
struct ui_file *gdb_stdlog;
|
||||
|
||||
static int remote_is_stdio = 0;
|
||||
|
||||
static gdb_fildes_t remote_desc = INVALID_DESCRIPTOR;
|
||||
static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR;
|
||||
|
||||
@ -130,6 +132,14 @@ gdb_connected (void)
|
||||
return remote_desc != INVALID_DESCRIPTOR;
|
||||
}
|
||||
|
||||
/* Return true if the remote connection is over stdio. */
|
||||
|
||||
int
|
||||
remote_connection_is_stdio (void)
|
||||
{
|
||||
return remote_is_stdio;
|
||||
}
|
||||
|
||||
static void
|
||||
enable_async_notification (int fd)
|
||||
{
|
||||
@ -222,6 +232,17 @@ remote_prepare (char *name)
|
||||
socklen_t tmp;
|
||||
char *port_end;
|
||||
|
||||
remote_is_stdio = 0;
|
||||
if (strcmp (name, STDIO_CONNECTION_NAME) == 0)
|
||||
{
|
||||
/* We need to record fact that we're using stdio sooner than the
|
||||
call to remote_open so start_inferior knows the connection is
|
||||
via stdio. */
|
||||
remote_is_stdio = 1;
|
||||
transport_is_reliable = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
port_str = strchr (name, ':');
|
||||
if (port_str == NULL)
|
||||
{
|
||||
@ -272,11 +293,27 @@ remote_open (char *name)
|
||||
char *port_str;
|
||||
|
||||
port_str = strchr (name, ':');
|
||||
if (port_str == NULL)
|
||||
{
|
||||
#ifdef USE_WIN32API
|
||||
error ("Only <host>:<port> is supported on this platform.");
|
||||
#else
|
||||
if (port_str == NULL)
|
||||
error ("Only <host>:<port> is supported on this platform.");
|
||||
#endif
|
||||
|
||||
if (strcmp (name, STDIO_CONNECTION_NAME) == 0)
|
||||
{
|
||||
fprintf (stderr, "Remote debugging using stdio\n");
|
||||
|
||||
/* Use stdin as the handle of the connection.
|
||||
We only select on reads, for example. */
|
||||
remote_desc = fileno (stdin);
|
||||
|
||||
enable_async_notification (remote_desc);
|
||||
|
||||
/* Register the event loop handler. */
|
||||
add_file_handler (remote_desc, handle_serial_event, NULL);
|
||||
}
|
||||
#ifndef USE_WIN32API
|
||||
else if (port_str == NULL)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat (name, &statbuf) == 0
|
||||
@ -341,8 +378,8 @@ remote_open (char *name)
|
||||
|
||||
/* Register the event loop handler. */
|
||||
add_file_handler (remote_desc, handle_serial_event, NULL);
|
||||
#endif /* USE_WIN32API */
|
||||
}
|
||||
#endif /* USE_WIN32API */
|
||||
else
|
||||
{
|
||||
int port;
|
||||
@ -372,7 +409,8 @@ remote_close (void)
|
||||
#ifdef USE_WIN32API
|
||||
closesocket (remote_desc);
|
||||
#else
|
||||
close (remote_desc);
|
||||
if (! remote_connection_is_stdio ())
|
||||
close (remote_desc);
|
||||
#endif
|
||||
remote_desc = INVALID_DESCRIPTOR;
|
||||
|
||||
@ -731,6 +769,32 @@ read_ptid (char *buf, char **obuf)
|
||||
return ptid_build (pid, tid, 0);
|
||||
}
|
||||
|
||||
/* Write COUNT bytes in BUF to the client.
|
||||
The result is the number of bytes written or -1 if error.
|
||||
This may return less than COUNT. */
|
||||
|
||||
static int
|
||||
write_prim (const void *buf, int count)
|
||||
{
|
||||
if (remote_connection_is_stdio ())
|
||||
return write (fileno (stdout), buf, count);
|
||||
else
|
||||
return write (remote_desc, buf, count);
|
||||
}
|
||||
|
||||
/* Read COUNT bytes from the client and store in BUF.
|
||||
The result is the number of bytes read or -1 if error.
|
||||
This may return less than COUNT. */
|
||||
|
||||
static int
|
||||
read_prim (void *buf, int count)
|
||||
{
|
||||
if (remote_connection_is_stdio ())
|
||||
return read (fileno (stdin), buf, count);
|
||||
else
|
||||
return read (remote_desc, buf, count);
|
||||
}
|
||||
|
||||
/* Send a packet to the remote machine, with error checking.
|
||||
The data of the packet is in BUF, and the length of the
|
||||
packet is in CNT. Returns >= 0 on success, -1 otherwise. */
|
||||
@ -768,7 +832,7 @@ putpkt_binary_1 (char *buf, int cnt, int is_notif)
|
||||
|
||||
do
|
||||
{
|
||||
if (write (remote_desc, buf2, p - buf2) != p - buf2)
|
||||
if (write_prim (buf2, p - buf2) != p - buf2)
|
||||
{
|
||||
perror ("putpkt(write)");
|
||||
free (buf2);
|
||||
@ -863,7 +927,7 @@ input_interrupt (int unused)
|
||||
int cc;
|
||||
char c = 0;
|
||||
|
||||
cc = read (remote_desc, &c, 1);
|
||||
cc = read_prim (&c, 1);
|
||||
|
||||
if (cc != 1 || c != '\003' || current_inferior == NULL)
|
||||
{
|
||||
@ -991,8 +1055,7 @@ readchar (void)
|
||||
|
||||
if (readchar_bufcnt == 0)
|
||||
{
|
||||
readchar_bufcnt = read (remote_desc, readchar_buf,
|
||||
sizeof (readchar_buf));
|
||||
readchar_bufcnt = read_prim (readchar_buf, sizeof (readchar_buf));
|
||||
|
||||
if (readchar_bufcnt <= 0)
|
||||
{
|
||||
@ -1114,7 +1177,7 @@ getpkt (char *buf)
|
||||
|
||||
fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
|
||||
(c1 << 4) + c2, csum, buf);
|
||||
if (write (remote_desc, "-", 1) != 1)
|
||||
if (write_prim ("-", 1) != 1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1126,7 +1189,7 @@ getpkt (char *buf)
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
if (write (remote_desc, "+", 1) != 1)
|
||||
if (write_prim ("+", 1) != 1)
|
||||
return -1;
|
||||
|
||||
if (remote_debug)
|
||||
|
@ -2606,6 +2606,13 @@ main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp (*next_arg, "-") == 0)
|
||||
{
|
||||
/* "-" specifies a stdio connection and is a form of port
|
||||
specification. */
|
||||
*next_arg = STDIO_CONNECTION_NAME;
|
||||
break;
|
||||
}
|
||||
else if (strcmp (*next_arg, "--disable-randomization") == 0)
|
||||
disable_randomization = 1;
|
||||
else if (strcmp (*next_arg, "--no-disable-randomization") == 0)
|
||||
@ -2636,6 +2643,12 @@ main (int argc, char *argv[])
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* We need to know whether the remote connection is stdio before
|
||||
starting the inferior. Inferiors created in this scenario have
|
||||
stdin,stdout redirected. So do this here before we call
|
||||
start_inferior. */
|
||||
remote_prepare (port);
|
||||
|
||||
bad_attach = 0;
|
||||
pid = 0;
|
||||
|
||||
@ -2723,8 +2736,6 @@ main (int argc, char *argv[])
|
||||
exit (1);
|
||||
}
|
||||
|
||||
remote_prepare (port);
|
||||
|
||||
while (1)
|
||||
{
|
||||
noack_mode = 0;
|
||||
|
@ -342,6 +342,9 @@ extern int transport_is_reliable;
|
||||
|
||||
int gdb_connected (void);
|
||||
|
||||
#define STDIO_CONNECTION_NAME "stdio"
|
||||
int remote_connection_is_stdio (void);
|
||||
|
||||
ptid_t read_ptid (char *buf, char **obuf);
|
||||
char *write_ptid (char *buf, ptid_t ptid);
|
||||
|
||||
|
@ -1,3 +1,11 @@
|
||||
2011-12-16 Doug Evans <dje@google.com>
|
||||
|
||||
* lib/gdbserver-support.exp (gdb_target_cmd): Recognize stdio
|
||||
gdbserver output.
|
||||
(gdbserver_default_get_remote_address): New function.
|
||||
(gdbserver_start): Call gdb,get_remote_address to compute argument
|
||||
to "target remote" command.
|
||||
|
||||
2011-12-16 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* gdb.python/py-function.exp: Change "on" to "full" for
|
||||
|
@ -70,6 +70,10 @@ proc gdb_target_cmd { targetname serialport } {
|
||||
verbose "Set target to $targetname"
|
||||
return 0
|
||||
}
|
||||
-re "Remote debugging using stdio.*$gdb_prompt $" {
|
||||
verbose "Set target to $targetname"
|
||||
return 0
|
||||
}
|
||||
-re "Remote target $targetname connected to.*$gdb_prompt $" {
|
||||
verbose "Set target to $targetname"
|
||||
return 0
|
||||
@ -183,6 +187,12 @@ proc gdbserver_download_current_prog { } {
|
||||
return $gdbserver_server_exec
|
||||
}
|
||||
|
||||
# Default routine to compute the argument to "target remote".
|
||||
|
||||
proc gdbserver_default_get_remote_address { host port } {
|
||||
return "$host$port"
|
||||
}
|
||||
|
||||
# Start a gdbserver process with initial OPTIONS and trailing ARGUMENTS.
|
||||
# The port will be filled in between them automatically.
|
||||
#
|
||||
@ -206,6 +216,15 @@ proc gdbserver_start { options arguments } {
|
||||
set debughost "localhost:"
|
||||
}
|
||||
|
||||
# Some boards use a different value for the port that is passed to
|
||||
# gdbserver and the port that is passed to the "target remote" command.
|
||||
# One example is the stdio gdbserver support.
|
||||
if [target_info exists gdb,get_remote_address] {
|
||||
set get_remote_address [target_info gdb,get_remote_address]
|
||||
} else {
|
||||
set get_remote_address gdbserver_default_get_remote_address
|
||||
}
|
||||
|
||||
# Extract the protocol
|
||||
if [target_info exists gdb_protocol] {
|
||||
set protocol [target_info gdb_protocol]
|
||||
@ -217,9 +236,6 @@ proc gdbserver_start { options arguments } {
|
||||
|
||||
# Loop till we find a free port.
|
||||
while 1 {
|
||||
# Export the host:port pair.
|
||||
set gdbport $debughost$portnum
|
||||
|
||||
# Fire off the debug agent.
|
||||
set gdbserver_command "$gdbserver"
|
||||
|
||||
@ -235,9 +251,9 @@ proc gdbserver_start { options arguments } {
|
||||
if { $options != "" } {
|
||||
append gdbserver_command " $options"
|
||||
}
|
||||
|
||||
append gdbserver_command " :$portnum"
|
||||
|
||||
if { $portnum != "" } {
|
||||
append gdbserver_command " :$portnum"
|
||||
}
|
||||
if { $arguments != "" } {
|
||||
append gdbserver_command " $arguments"
|
||||
}
|
||||
@ -275,7 +291,7 @@ proc gdbserver_start { options arguments } {
|
||||
}
|
||||
}
|
||||
|
||||
return [list $protocol $gdbport]
|
||||
return [list $protocol [$get_remote_address $debughost $portnum]]
|
||||
}
|
||||
|
||||
# Start a gdbserver process running SERVER_EXEC, and connect GDB
|
||||
|
Loading…
x
Reference in New Issue
Block a user