* linux-low.c (linux_attach_lwp): Do not _exit after errors.
(linux_kill, linux_detach): Clean up the process list. * remote-utils.c (remote_open): Improve port number parsing. (putpkt_binary, input_interrupt): Only send interrupts if the target is running. * server.c (extended_protocol): Make static. (attached): Define earlier. (exit_requested, response_needed, program_argv): New variables. (target_running): New. (start_inferior): Clear attached here. (attach_inferior): Set attached here. (require_running): Define. (handle_query): Use require_running and target_running. Implement "monitor exit". (handle_v_attach, handle_v_run): New. (handle_v_requests): Use require_running. Handle vAttach and vRun. (gdbserver_usage): Update. (main): Redo argument parsing. Handle --debug and --multi. Handle --attach along with other options or after the port. Save program_argv. Support no initial program. Resynchronize communication with GDB after an error. Handle "monitor exit". Use require_running and target_running. Always allow the extended protocol. Do not error out for Hc0 or Hc-1. Do not automatically restart in extended mode. * README: Refer to the GDB manual. Update --attach usage. * remote.c (struct remote_state): Add cached_wait_status. (remote_exec_file): New variable. (PACKET_vAttach, PACKET_vRun): New constants. (extended_remote_restart): Do not query for status. (struct start_remote_args): New. (remote_start_remote): Take it as a second argument. Check whether the target is running. Issue an error for non-running non-extended targets. Cache the wait status. Set inferior_ptid here. (remote_open_1): Prompt to disconnect non-running targets. Make sure the target is marked running. Do not set inferior_ptid here. Update call to remote_start_remote. Do not call remote_check_symbols if the target is not running. (remote_detach_1): Rename from remote_detach. Take an EXTENDED argument. Handle a non-running target. (remote_detach): Use it. (extended_remote_detach): New. (remote_disconnect): Fix typo. Use remoute_mourn_1. (extended_remote_attach_1, extended_remote_attach) (extended_async_remote_attach): New. (remote_vcont_resume): Remove unused variable. (remote_wait, remote_async_wait): Use any cached wait status. (putpkt_binary, getpkt): Clear any cached wait status. (extended_remoute_mourn_1): New. (extended_remote_mourn): Use it. (extended_async_remote_mourn, extended_remote_run): New. (extended_remote_create_inferior_1): New. (extended_remote_create_inferior): Use it. (extended_remote_async_create_inferior): Likewise. (remote_xfer_partial): Skip for non-executing targets. (init_extended_remote_ops): Set to_detach and to_attach. (init_extended_async_remote_ops): Likewise. Use extended_async_remote_mourn. (_initialize_remote): Register vAttach, vRun, and set remote exec-file. * NEWS: Mention vAttach, vRun, and gdbserver extended-remote support. * gdb.server/ext-attach.c, gdb.server/ext-attach.exp, gdb.server/ext-run.exp: New files. * lib/gdbserver-support.exp (gdbserver_download): New. (gdbserver_start): New. Update gdbserver expected output. (gdbserver_spawn): Use them. (gdbserver_start_extended): New. * gdb.texinfo (Using the `gdbserver' Program): Add security warning. Rearrange into subsections and subsubsections. Document --multi and --debug. Correct --with-sysroot typo. Update --attach usage. Make load reference clearer. Document monitor exit. (Remote Configuration): Document set remote exec-file, attach-packet, and run-packet. (Packets): Document vAttach and vRun.
This commit is contained in:
parent
9dc513fc0e
commit
2d717e4f8a
@ -1,3 +1,42 @@
|
||||
2008-01-29 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* remote.c (struct remote_state): Add cached_wait_status.
|
||||
(remote_exec_file): New variable.
|
||||
(PACKET_vAttach, PACKET_vRun): New constants.
|
||||
(extended_remote_restart): Do not query for status.
|
||||
(struct start_remote_args): New.
|
||||
(remote_start_remote): Take it as a second argument. Check
|
||||
whether the target is running. Issue an error for non-running
|
||||
non-extended targets. Cache the wait status. Set inferior_ptid
|
||||
here.
|
||||
(remote_open_1): Prompt to disconnect non-running targets. Make
|
||||
sure the target is marked running. Do not set inferior_ptid here.
|
||||
Update call to remote_start_remote. Do not call remote_check_symbols
|
||||
if the target is not running.
|
||||
(remote_detach_1): Rename from remote_detach. Take an EXTENDED
|
||||
argument. Handle a non-running target.
|
||||
(remote_detach): Use it.
|
||||
(extended_remote_detach): New.
|
||||
(remote_disconnect): Fix typo. Use remoute_mourn_1.
|
||||
(extended_remote_attach_1, extended_remote_attach)
|
||||
(extended_async_remote_attach): New.
|
||||
(remote_vcont_resume): Remove unused variable.
|
||||
(remote_wait, remote_async_wait): Use any cached wait status.
|
||||
(putpkt_binary, getpkt): Clear any cached wait status.
|
||||
(extended_remoute_mourn_1): New.
|
||||
(extended_remote_mourn): Use it.
|
||||
(extended_async_remote_mourn, extended_remote_run): New.
|
||||
(extended_remote_create_inferior_1): New.
|
||||
(extended_remote_create_inferior): Use it.
|
||||
(extended_remote_async_create_inferior): Likewise.
|
||||
(remote_xfer_partial): Skip for non-executing targets.
|
||||
(init_extended_remote_ops): Set to_detach and to_attach.
|
||||
(init_extended_async_remote_ops): Likewise. Use
|
||||
extended_async_remote_mourn.
|
||||
(_initialize_remote): Register vAttach, vRun, and
|
||||
set remote exec-file.
|
||||
* NEWS: Mention vAttach, vRun, and gdbserver extended-remote support.
|
||||
|
||||
2008-01-29 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* Makefile.in (symfile.o): Update.
|
||||
|
10
gdb/NEWS
10
gdb/NEWS
@ -50,6 +50,9 @@ targets even when the libthread_db library is not available.
|
||||
* The GDB remote stub, gdbserver, now supports the new file transfer
|
||||
commands (remote put, remote get, and remote delete).
|
||||
|
||||
* The GDB remote stub, gdbserver, now supports run and attach in
|
||||
extended-remote mode.
|
||||
|
||||
* hppa*64*-*-hpux11* target broken
|
||||
The debugger is unable to start a program and fails with the following
|
||||
error: "Error trying to get information about dynamic linker".
|
||||
@ -85,6 +88,13 @@ vFile:unlink:
|
||||
* GDB on GNU/Linux and HP/UX can now debug through "exec" of a new
|
||||
process.
|
||||
|
||||
vAttach
|
||||
Attach to an existing process on the remote system, in extended-remote
|
||||
mode.
|
||||
|
||||
vRun
|
||||
Run a new process on the remote system, in extended-remote mode.
|
||||
|
||||
*** Changes in GDB 6.7
|
||||
|
||||
* Resolved 101 resource leaks, null pointer dereferences, etc. in gdb,
|
||||
|
@ -1,3 +1,13 @@
|
||||
2008-01-29 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (Using the `gdbserver' Program): Add security
|
||||
warning. Rearrange into subsections and subsubsections. Document
|
||||
--multi and --debug. Correct --with-sysroot typo. Update --attach
|
||||
usage. Make load reference clearer. Document monitor exit.
|
||||
(Remote Configuration): Document set remote exec-file, attach-packet,
|
||||
and run-packet.
|
||||
(Packets): Document vAttach and vRun.
|
||||
|
||||
2008-01-30 Nick Roberts <nickrob@snap.net.nz>
|
||||
|
||||
* gdb.texinfo (Processes): Mention process command.
|
||||
|
@ -12952,9 +12952,19 @@ choice for debugging.
|
||||
or a TCP connection, using the standard @value{GDBN} remote serial
|
||||
protocol.
|
||||
|
||||
@table @emph
|
||||
@item On the target machine,
|
||||
you need to have a copy of the program you want to debug.
|
||||
@quotation
|
||||
@emph{Warning:} @code{gdbserver} does not have any built-in security.
|
||||
Do not run @code{gdbserver} connected to any public network; a
|
||||
@value{GDBN} connection to @code{gdbserver} provides access to the
|
||||
target system with the same privileges as the user running
|
||||
@code{gdbserver}.
|
||||
@end quotation
|
||||
|
||||
@subsection Running @code{gdbserver}
|
||||
@cindex arguments, to @code{gdbserver}
|
||||
|
||||
Run @code{gdbserver} on the target system. You need a copy of the
|
||||
program you want to debug, including any libraries it requires.
|
||||
@code{gdbserver} does not need your program's symbol table, so you can
|
||||
strip the program if necessary to save space. @value{GDBN} on the host
|
||||
system does all the symbol handling.
|
||||
@ -12997,11 +13007,13 @@ 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.
|
||||
|
||||
@subsubsection Attaching to a Running Program
|
||||
|
||||
On some targets, @code{gdbserver} can also attach to running programs.
|
||||
This is accomplished via the @code{--attach} argument. The syntax is:
|
||||
|
||||
@smallexample
|
||||
target> gdbserver @var{comm} --attach @var{pid}
|
||||
target> gdbserver --attach @var{comm} @var{pid}
|
||||
@end smallexample
|
||||
|
||||
@var{pid} is the process ID of a currently running process. It isn't necessary
|
||||
@ -13013,18 +13025,56 @@ You can debug processes by name instead of process ID if your target has the
|
||||
@code{pidof} utility:
|
||||
|
||||
@smallexample
|
||||
target> gdbserver @var{comm} --attach `pidof @var{program}`
|
||||
target> gdbserver --attach @var{comm} `pidof @var{program}`
|
||||
@end smallexample
|
||||
|
||||
In case more than one copy of @var{program} is running, or @var{program}
|
||||
has multiple threads, most versions of @code{pidof} support the
|
||||
@code{-s} option to only return the first process ID.
|
||||
|
||||
@item On the host machine,
|
||||
first make sure you have the necessary symbol files. Load symbols for
|
||||
@subsubsection Multi-Process Mode for @code{gdbserver}
|
||||
@cindex gdbserver, multiple processes
|
||||
@cindex multiple processes with gdbserver
|
||||
|
||||
When you connect to @code{gdbserver} using @code{target remote},
|
||||
@code{gdbserver} debugs the specified program only once. When the
|
||||
program exits, or you detach from it, @value{GDBN} closes the connection
|
||||
and @code{gdbserver} exits.
|
||||
|
||||
If you connect using @code{target extended-remote}, @code{gdbserver}
|
||||
enters multi-process mode. When the debugged program exits, or you
|
||||
detach from it, @value{GDBN} stays connected to @code{gdbserver} even
|
||||
though no program is running. The @code{run} and @code{attach}
|
||||
commands instruct @code{gdbserver} to run or attach to a new program.
|
||||
The @code{run} command uses @code{set remote exec-file} (@pxref{set
|
||||
remote exec-file}) to select the program to run. Command line
|
||||
arguments are supported, except for wildcard expansion and I/O
|
||||
redirection (@pxref{Arguments}).
|
||||
|
||||
To start @code{gdbserver} without supplying an initial command to run
|
||||
or process ID to attach, use the @option{--multi} command line option.
|
||||
Then you can connect using @code{target extended-remote} and start
|
||||
the program you want to debug.
|
||||
|
||||
@code{gdbserver} does not automatically exit in multi-process mode.
|
||||
You can terminate it by using @code{monitor exit}
|
||||
(@pxref{Monitor Commands for gdbserver}).
|
||||
|
||||
@subsubsection Other Command-Line Arguments for @code{gdbserver}
|
||||
|
||||
You can include @option{--debug} on the @code{gdbserver} command line.
|
||||
@code{gdbserver} will display extra status information about the debugging
|
||||
process. This option is intended for @code{gdbserver} development and
|
||||
for bug reports to the developers.
|
||||
|
||||
@subsection Connecting to @code{gdbserver}
|
||||
|
||||
Run @value{GDBN} on the host system.
|
||||
|
||||
First make sure you have the necessary symbol files. Load symbols for
|
||||
your application using the @code{file} command before you connect. Use
|
||||
@code{set sysroot} to locate target libraries (unless your @value{GDBN}
|
||||
was compiled with the correct sysroot using @code{--with-system-root}).
|
||||
was compiled with the correct sysroot using @code{--with-sysroot}).
|
||||
|
||||
The symbol file and target libraries must exactly match the executable
|
||||
and libraries on the target, with one exception: the files on the host
|
||||
@ -13038,19 +13088,17 @@ Connect to your target (@pxref{Connecting,,Connecting to a Remote Target}).
|
||||
For TCP connections, you must start up @code{gdbserver} prior to using
|
||||
the @code{target remote} command. Otherwise you may get an error whose
|
||||
text depends on the host system, but which usually looks something like
|
||||
@samp{Connection refused}. You don't need to use the @code{load}
|
||||
@samp{Connection refused}. Don't use the @code{load}
|
||||
command in @value{GDBN} when using @code{gdbserver}, since the program is
|
||||
already on the target.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Monitor Commands for @code{gdbserver}
|
||||
@cindex monitor commands, for @code{gdbserver}
|
||||
@anchor{Monitor Commands for gdbserver}
|
||||
|
||||
During a @value{GDBN} session using @code{gdbserver}, you can use the
|
||||
@code{monitor} command to send special requests to @code{gdbserver}.
|
||||
Here are the available commands; they are only of interest when
|
||||
debugging @value{GDBN} or @code{gdbserver}.
|
||||
Here are the available commands.
|
||||
|
||||
@table @code
|
||||
@item monitor help
|
||||
@ -13065,6 +13113,13 @@ Disable or enable general debugging messages.
|
||||
Disable or enable specific debugging messages associated with the remote
|
||||
protocol (@pxref{Remote Protocol}).
|
||||
|
||||
@item monitor exit
|
||||
Tell gdbserver to exit immediately. This command should be followed by
|
||||
@code{disconnect} to close the debugging session. @code{gdbserver} will
|
||||
detach from any attached processes and kill any processes it created.
|
||||
Use @code{monitor exit} to terminate @code{gdbserver} at the end
|
||||
of a multi-process mode debug session.
|
||||
|
||||
@end table
|
||||
|
||||
@node Remote Configuration
|
||||
@ -13159,6 +13214,15 @@ responses.
|
||||
@itemx set remote hardware-breakpoint-limit @var{limit}
|
||||
Restrict @value{GDBN} to using @var{limit} remote hardware breakpoint or
|
||||
watchpoints. A limit of -1, the default, is treated as unlimited.
|
||||
|
||||
@item set remote exec-file @var{filename}
|
||||
@itemx show remote exec-file
|
||||
@anchor{set remote exec-file}
|
||||
@cindex executable file, for remote target
|
||||
Select the file used for @code{run} with @code{target
|
||||
extended-remote}. This should be set to a filename valid on the
|
||||
target system. If it is not set, the target will use a default
|
||||
filename (e.g.@: the last program run).
|
||||
@end table
|
||||
|
||||
@cindex remote packets, enabling and disabling
|
||||
@ -13205,10 +13269,18 @@ are:
|
||||
@tab @code{qSymbol}
|
||||
@tab Detecting multiple threads
|
||||
|
||||
@item @code{attach}
|
||||
@tab @code{vAttach}
|
||||
@tab @code{attach}
|
||||
|
||||
@item @code{verbose-resume}
|
||||
@tab @code{vCont}
|
||||
@tab Stepping or resuming multiple threads
|
||||
|
||||
@item @code{run}
|
||||
@tab @code{vRun}
|
||||
@tab @code{run}
|
||||
|
||||
@item @code{software-breakpoint}
|
||||
@tab @code{Z0}
|
||||
@tab @code{break}
|
||||
@ -23298,6 +23370,7 @@ Here are the packet descriptions.
|
||||
|
||||
@item !
|
||||
@cindex @samp{!} packet
|
||||
@anchor{extended mode}
|
||||
Enable extended mode. In extended mode, the remote server is made
|
||||
persistent. The @samp{R} packet is used to restart the program being
|
||||
debugged.
|
||||
@ -23563,7 +23636,7 @@ Don't use this packet; use the @samp{R} packet instead.
|
||||
@item R @var{XX}
|
||||
@cindex @samp{R} packet
|
||||
Restart the program being debugged. @var{XX}, while needed, is ignored.
|
||||
This packet is only available in extended mode.
|
||||
This packet is only available in extended mode (@pxref{extended mode}).
|
||||
|
||||
The @samp{R} packet has no reply.
|
||||
|
||||
@ -23606,6 +23679,22 @@ thread is dead
|
||||
Packets starting with @samp{v} are identified by a multi-letter name,
|
||||
up to the first @samp{;} or @samp{?} (or the end of the packet).
|
||||
|
||||
@item vAttach;@var{pid}
|
||||
@cindex @samp{vAttach} packet
|
||||
Attach to a new process with the specified process ID. @var{pid} is a
|
||||
hexadecimal integer identifying the process. If the stub is currently
|
||||
controlling a process, it is killed. The attached process is stopped.
|
||||
|
||||
This packet is only available in extended mode (@pxref{extended mode}).
|
||||
|
||||
Reply:
|
||||
@table @samp
|
||||
@item E @var{nn}
|
||||
for an error
|
||||
@item @r{Any stop packet}
|
||||
for success (@pxref{Stop Reply Packets})
|
||||
@end table
|
||||
|
||||
@item vCont@r{[};@var{action}@r{[}:@var{tid}@r{]]}@dots{}
|
||||
@cindex @samp{vCont} packet
|
||||
Resume the inferior, specifying different actions for each thread.
|
||||
@ -23702,6 +23791,24 @@ The stub is permitted to delay or batch the effects of a group of
|
||||
regions of flash memory are unpredictable until the @samp{vFlashDone}
|
||||
request is completed.
|
||||
|
||||
@item vRun;@var{filename}@r{[};@var{argument}@r{]}@dots{}
|
||||
@cindex @samp{vRun} packet
|
||||
Run the program @var{filename}, passing it each @var{argument} on its
|
||||
command line. The file and arguments are hex-encoded strings. If
|
||||
@var{filename} is an empty string, the stub may use a default program
|
||||
(e.g.@: the last program run). The program is created in the stopped
|
||||
state. If the stub is currently controlling a process, it is killed.
|
||||
|
||||
This packet is only available in extended mode (@pxref{extended mode}).
|
||||
|
||||
Reply:
|
||||
@table @samp
|
||||
@item E @var{nn}
|
||||
for an error
|
||||
@item @r{Any stop packet}
|
||||
for success (@pxref{Stop Reply Packets})
|
||||
@end table
|
||||
|
||||
@item X @var{addr},@var{length}:@var{XX@dots{}}
|
||||
@anchor{X packet}
|
||||
@cindex @samp{X} packet
|
||||
|
@ -1,3 +1,31 @@
|
||||
2008-01-29 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* linux-low.c (linux_attach_lwp): Do not _exit after errors.
|
||||
(linux_kill, linux_detach): Clean up the process list.
|
||||
* remote-utils.c (remote_open): Improve port number parsing.
|
||||
(putpkt_binary, input_interrupt): Only send interrupts if the target
|
||||
is running.
|
||||
* server.c (extended_protocol): Make static.
|
||||
(attached): Define earlier.
|
||||
(exit_requested, response_needed, program_argv): New variables.
|
||||
(target_running): New.
|
||||
(start_inferior): Clear attached here.
|
||||
(attach_inferior): Set attached here.
|
||||
(require_running): Define.
|
||||
(handle_query): Use require_running and target_running. Implement
|
||||
"monitor exit".
|
||||
(handle_v_attach, handle_v_run): New.
|
||||
(handle_v_requests): Use require_running. Handle vAttach and vRun.
|
||||
(gdbserver_usage): Update.
|
||||
(main): Redo argument parsing. Handle --debug and --multi. Handle
|
||||
--attach along with other options or after the port. Save
|
||||
program_argv. Support no initial program. Resynchronize
|
||||
communication with GDB after an error. Handle "monitor exit".
|
||||
Use require_running and target_running. Always allow the extended
|
||||
protocol. Do not error out for Hc0 or Hc-1. Do not automatically
|
||||
restart in extended mode.
|
||||
* README: Refer to the GDB manual. Update --attach usage.
|
||||
|
||||
2007-12-20 Andreas Schwab <schwab@suse.de>
|
||||
|
||||
* linux-low.c (STACK_SIZE): Define.
|
||||
|
@ -9,6 +9,8 @@ host. GDB and GDBserver communicate using the standard remote serial protocol
|
||||
implemented in remote.c, and various *-stub.c files. They communicate via
|
||||
either a serial line or a TCP connection.
|
||||
|
||||
For more information about GDBserver, see the GDB manual.
|
||||
|
||||
Usage (server (target) side):
|
||||
|
||||
First, you need to have a copy of the program you want to debug put onto
|
||||
@ -47,7 +49,7 @@ print an error message and exit.
|
||||
On some targets, gdbserver can also attach to running programs. This is
|
||||
accomplished via the --attach argument. The syntax is:
|
||||
|
||||
target> gdbserver COMM --attach PID
|
||||
target> gdbserver --attach COMM PID
|
||||
|
||||
PID is the process ID of a currently running process. It isn't necessary
|
||||
to point gdbserver at a binary for the running process.
|
||||
|
@ -304,14 +304,18 @@ linux_attach_lwp (unsigned long pid)
|
||||
|
||||
if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
|
||||
{
|
||||
fprintf (stderr, "Cannot attach to process %ld: %s (%d)\n", pid,
|
||||
if (all_threads.head != NULL)
|
||||
{
|
||||
/* If we fail to attach to an LWP, just warn. */
|
||||
fprintf (stderr, "Cannot attach to process %ld: %s (%d)\n", pid,
|
||||
strerror (errno), errno);
|
||||
fflush (stderr);
|
||||
return;
|
||||
}
|
||||
else
|
||||
/* If we fail to attach to a process, report an error. */
|
||||
error ("Cannot attach to process %ld: %s (%d)\n", pid,
|
||||
strerror (errno), errno);
|
||||
fflush (stderr);
|
||||
|
||||
/* If we fail to attach to an LWP, just return. */
|
||||
if (all_threads.head == NULL)
|
||||
_exit (0177);
|
||||
return;
|
||||
}
|
||||
|
||||
ptrace (PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACECLONE);
|
||||
@ -396,6 +400,10 @@ linux_kill (void)
|
||||
/* Make sure it died. The loop is most likely unnecessary. */
|
||||
wstat = linux_wait_for_event (thread);
|
||||
} while (WIFSTOPPED (wstat));
|
||||
|
||||
clear_inferiors ();
|
||||
free (all_processes.head);
|
||||
all_processes.head = all_processes.tail = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -434,6 +442,8 @@ linux_detach (void)
|
||||
delete_all_breakpoints ();
|
||||
for_each_inferior (&all_threads, linux_detach_one_process);
|
||||
clear_inferiors ();
|
||||
free (all_processes.head);
|
||||
all_processes.head = all_processes.tail = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -187,15 +187,15 @@ remote_open (char *name)
|
||||
#ifdef USE_WIN32API
|
||||
static int winsock_initialized;
|
||||
#endif
|
||||
char *port_str;
|
||||
int port;
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t tmp;
|
||||
int tmp_desc;
|
||||
char *port_end;
|
||||
|
||||
port_str = strchr (name, ':');
|
||||
|
||||
port = atoi (port_str + 1);
|
||||
port = strtoul (port_str + 1, &port_end, 10);
|
||||
if (port_str[1] == '\0' || *port_end != '\0')
|
||||
fatal ("Bad port argument: %s", name);
|
||||
|
||||
#ifdef USE_WIN32API
|
||||
if (!winsock_initialized)
|
||||
@ -575,7 +575,7 @@ putpkt_binary (char *buf, int cnt)
|
||||
}
|
||||
|
||||
/* Check for an input interrupt while we're here. */
|
||||
if (buf3[0] == '\003')
|
||||
if (buf3[0] == '\003' && current_inferior != NULL)
|
||||
(*the_target->request_interrupt) ();
|
||||
}
|
||||
while (buf3[0] != '+');
|
||||
@ -617,7 +617,7 @@ input_interrupt (int unused)
|
||||
|
||||
cc = read (remote_desc, &c, 1);
|
||||
|
||||
if (cc != 1 || c != '\003')
|
||||
if (cc != 1 || c != '\003' || current_inferior == NULL)
|
||||
{
|
||||
fprintf (stderr, "input_interrupt, count = %d c = %d ('%c')\n",
|
||||
cc, c, c);
|
||||
|
@ -34,9 +34,15 @@ unsigned long general_thread;
|
||||
unsigned long step_thread;
|
||||
unsigned long thread_from_wait;
|
||||
unsigned long old_thread_from_wait;
|
||||
int extended_protocol;
|
||||
int server_waiting;
|
||||
|
||||
static int extended_protocol;
|
||||
static int attached;
|
||||
static int response_needed;
|
||||
static int exit_requested;
|
||||
|
||||
static char **program_argv;
|
||||
|
||||
/* Enable miscellaneous debugging output. The name is historical - it
|
||||
was originally used to debug LinuxThreads support. */
|
||||
int debug_threads;
|
||||
@ -68,9 +74,17 @@ restore_old_foreground_pgrp (void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
target_running (void)
|
||||
{
|
||||
return all_threads.head != NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
start_inferior (char *argv[], char *statusptr)
|
||||
{
|
||||
attached = 0;
|
||||
|
||||
#ifdef SIGTTOU
|
||||
signal (SIGTTOU, SIG_DFL);
|
||||
signal (SIGTTIN, SIG_DFL);
|
||||
@ -107,6 +121,8 @@ attach_inferior (int pid, char *statusptr, int *sigptr)
|
||||
if (myattach (pid) != 0)
|
||||
return -1;
|
||||
|
||||
attached = 1;
|
||||
|
||||
fprintf (stderr, "Attached; pid = %d\n", pid);
|
||||
fflush (stderr);
|
||||
|
||||
@ -254,6 +270,13 @@ monitor_show_help (void)
|
||||
monitor_output (" Enable remote protocol debugging messages\n");
|
||||
}
|
||||
|
||||
#define require_running(BUF) \
|
||||
if (!target_running ()) \
|
||||
{ \
|
||||
write_enn (BUF); \
|
||||
return; \
|
||||
}
|
||||
|
||||
/* Handle all of the extended 'q' packets. */
|
||||
void
|
||||
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
@ -263,6 +286,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
/* Reply the current thread id. */
|
||||
if (strcmp ("qC", own_buf) == 0)
|
||||
{
|
||||
require_running (own_buf);
|
||||
thread_ptr = all_threads.head;
|
||||
sprintf (own_buf, "QC%x",
|
||||
thread_to_gdb_id ((struct thread_info *)thread_ptr));
|
||||
@ -271,7 +295,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
|
||||
if (strcmp ("qSymbol::", own_buf) == 0)
|
||||
{
|
||||
if (the_target->look_up_symbols != NULL)
|
||||
if (target_running () && the_target->look_up_symbols != NULL)
|
||||
(*the_target->look_up_symbols) ();
|
||||
|
||||
strcpy (own_buf, "OK");
|
||||
@ -280,6 +304,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
|
||||
if (strcmp ("qfThreadInfo", own_buf) == 0)
|
||||
{
|
||||
require_running (own_buf);
|
||||
thread_ptr = all_threads.head;
|
||||
sprintf (own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr));
|
||||
thread_ptr = thread_ptr->next;
|
||||
@ -288,6 +313,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
|
||||
if (strcmp ("qsThreadInfo", own_buf) == 0)
|
||||
{
|
||||
require_running (own_buf);
|
||||
if (thread_ptr != NULL)
|
||||
{
|
||||
sprintf (own_buf, "m%x", thread_to_gdb_id ((struct thread_info *)thread_ptr));
|
||||
@ -305,7 +331,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
&& strcmp ("qOffsets", own_buf) == 0)
|
||||
{
|
||||
CORE_ADDR text, data;
|
||||
|
||||
|
||||
require_running (own_buf);
|
||||
if (the_target->read_offsets (&text, &data))
|
||||
sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX",
|
||||
(long)text, (long)data, (long)data);
|
||||
@ -324,6 +351,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
CORE_ADDR ofs;
|
||||
unsigned char *spu_buf;
|
||||
|
||||
require_running (own_buf);
|
||||
strcpy (own_buf, "E00");
|
||||
if (decode_xfer_read (own_buf + 15, &annex, &ofs, &len) < 0)
|
||||
return;
|
||||
@ -356,6 +384,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
CORE_ADDR ofs;
|
||||
unsigned char *spu_buf;
|
||||
|
||||
require_running (own_buf);
|
||||
strcpy (own_buf, "E00");
|
||||
spu_buf = malloc (packet_len - 15);
|
||||
if (!spu_buf)
|
||||
@ -387,6 +416,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
unsigned int len;
|
||||
char *annex;
|
||||
|
||||
require_running (own_buf);
|
||||
|
||||
/* Reject any annex; grab the offset and length. */
|
||||
if (decode_xfer_read (own_buf + 16, &annex, &ofs, &len) < 0
|
||||
|| annex[0] != '\0')
|
||||
@ -420,6 +451,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
const char *document;
|
||||
char *annex;
|
||||
|
||||
require_running (own_buf);
|
||||
|
||||
/* Check for support. */
|
||||
document = get_features_xml ("target.xml");
|
||||
if (document == NULL)
|
||||
@ -467,6 +500,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
struct inferior_list_entry *dll_ptr;
|
||||
char *annex;
|
||||
|
||||
require_running (own_buf);
|
||||
|
||||
/* Reject any annex; grab the offset and length. */
|
||||
if (decode_xfer_read (own_buf + 21, &annex, &ofs, &len) < 0
|
||||
|| annex[0] != '\0')
|
||||
@ -535,7 +570,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
|
||||
if (the_target->read_auxv != NULL)
|
||||
strcat (own_buf, ";qXfer:auxv:read+");
|
||||
|
||||
|
||||
if (the_target->qxfer_spu != NULL)
|
||||
strcat (own_buf, ";qXfer:spu:read+;qXfer:spu:write+");
|
||||
|
||||
@ -553,6 +588,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
CORE_ADDR parts[3], address = 0;
|
||||
int i, err;
|
||||
|
||||
require_running (own_buf);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
char *p2;
|
||||
@ -642,6 +679,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||
}
|
||||
else if (strcmp (mon, "help") == 0)
|
||||
monitor_show_help ();
|
||||
else if (strcmp (mon, "exit") == 0)
|
||||
exit_requested = 1;
|
||||
else
|
||||
{
|
||||
monitor_output ("Unknown monitor command.\n\n");
|
||||
@ -772,6 +811,95 @@ err:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Attach to a new program. Return 1 if successful, 0 if failure. */
|
||||
int
|
||||
handle_v_attach (char *own_buf, char *status, int *signal)
|
||||
{
|
||||
int pid;
|
||||
|
||||
pid = strtol (own_buf + 8, NULL, 16);
|
||||
if (pid != 0 && attach_inferior (pid, status, signal) == 0)
|
||||
{
|
||||
prepare_resume_reply (own_buf, *status, *signal);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_enn (own_buf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run a new program. Return 1 if successful, 0 if failure. */
|
||||
static int
|
||||
handle_v_run (char *own_buf, char *status, int *signal)
|
||||
{
|
||||
char *p, **pp, *next_p, **new_argv;
|
||||
int i, new_argc;
|
||||
|
||||
new_argc = 0;
|
||||
for (p = own_buf + strlen ("vRun;"); p && *p; p = strchr (p, ';'))
|
||||
{
|
||||
p++;
|
||||
new_argc++;
|
||||
}
|
||||
|
||||
new_argv = malloc ((new_argc + 2) * sizeof (char *));
|
||||
i = 0;
|
||||
for (p = own_buf + strlen ("vRun;"); *p; p = next_p)
|
||||
{
|
||||
next_p = strchr (p, ';');
|
||||
if (next_p == NULL)
|
||||
next_p = p + strlen (p);
|
||||
|
||||
if (i == 0 && p == next_p)
|
||||
new_argv[i] = NULL;
|
||||
else
|
||||
{
|
||||
new_argv[i] = malloc (1 + (next_p - p) / 2);
|
||||
unhexify (new_argv[i], p, (next_p - p) / 2);
|
||||
new_argv[i][(next_p - p) / 2] = '\0';
|
||||
}
|
||||
|
||||
if (*next_p)
|
||||
next_p++;
|
||||
i++;
|
||||
}
|
||||
new_argv[i] = NULL;
|
||||
|
||||
if (new_argv[0] == NULL)
|
||||
{
|
||||
if (program_argv == NULL)
|
||||
{
|
||||
write_enn (own_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_argv[0] = strdup (program_argv[0]);
|
||||
}
|
||||
|
||||
/* Free the old argv. */
|
||||
if (program_argv)
|
||||
{
|
||||
for (pp = program_argv; *pp != NULL; pp++)
|
||||
free (*pp);
|
||||
free (program_argv);
|
||||
}
|
||||
program_argv = new_argv;
|
||||
|
||||
*signal = start_inferior (program_argv, status);
|
||||
if (*status == 'T')
|
||||
{
|
||||
prepare_resume_reply (own_buf, *status, *signal);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_enn (own_buf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle all of the extended 'v' packets. */
|
||||
void
|
||||
handle_v_requests (char *own_buf, char *status, int *signal,
|
||||
@ -779,6 +907,7 @@ handle_v_requests (char *own_buf, char *status, int *signal,
|
||||
{
|
||||
if (strncmp (own_buf, "vCont;", 6) == 0)
|
||||
{
|
||||
require_running (own_buf);
|
||||
handle_v_cont (own_buf, status, signal);
|
||||
return;
|
||||
}
|
||||
@ -793,6 +922,28 @@ handle_v_requests (char *own_buf, char *status, int *signal,
|
||||
&& handle_vFile (own_buf, packet_len, new_packet_len))
|
||||
return;
|
||||
|
||||
if (strncmp (own_buf, "vAttach;", 8) == 0)
|
||||
{
|
||||
if (target_running ())
|
||||
{
|
||||
fprintf (stderr, "Killing inferior\n");
|
||||
kill_inferior ();
|
||||
}
|
||||
handle_v_attach (own_buf, status, signal);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp (own_buf, "vRun;", 5) == 0)
|
||||
{
|
||||
if (target_running ())
|
||||
{
|
||||
fprintf (stderr, "Killing inferior\n");
|
||||
kill_inferior ();
|
||||
}
|
||||
handle_v_run (own_buf, status, signal);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise we didn't know what packet it was. Say we didn't
|
||||
understand it. */
|
||||
own_buf[0] = 0;
|
||||
@ -829,8 +980,6 @@ myresume (char *own_buf, int step, int *signalp, char *statusp)
|
||||
disable_async_io ();
|
||||
}
|
||||
|
||||
static int attached;
|
||||
|
||||
static void
|
||||
gdbserver_version (void)
|
||||
{
|
||||
@ -844,13 +993,25 @@ gdbserver_version (void)
|
||||
static void
|
||||
gdbserver_usage (void)
|
||||
{
|
||||
printf ("Usage:\tgdbserver COMM PROG [ARGS ...]\n"
|
||||
"\tgdbserver COMM --attach PID\n"
|
||||
printf ("Usage:\tgdbserver [OPTIONS] COMM PROG [ARGS ...]\n"
|
||||
"\tgdbserver [OPTIONS] --attach COMM PID\n"
|
||||
"\tgdbserver [OPTIONS] --multi COMM\n"
|
||||
"\n"
|
||||
"COMM may either be a tty device (for serial debugging), or \n"
|
||||
"HOST:PORT to listen for a TCP connection.\n");
|
||||
"HOST:PORT to listen for a TCP connection.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" --debug\t\tEnable debugging output.\n");
|
||||
}
|
||||
|
||||
#undef require_running
|
||||
#define require_running(BUF) \
|
||||
if (!target_running ()) \
|
||||
{ \
|
||||
write_enn (BUF); \
|
||||
break; \
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@ -862,18 +1023,38 @@ main (int argc, char *argv[])
|
||||
CORE_ADDR mem_addr;
|
||||
int bad_attach;
|
||||
int pid;
|
||||
char *arg_end;
|
||||
char *arg_end, *port;
|
||||
char **next_arg = &argv[1];
|
||||
int multi_mode = 0;
|
||||
int attach = 0;
|
||||
int was_running;
|
||||
|
||||
if (argc >= 2 && strcmp (argv[1], "--version") == 0)
|
||||
while (*next_arg != NULL && **next_arg == '-')
|
||||
{
|
||||
gdbserver_version ();
|
||||
exit (0);
|
||||
}
|
||||
if (strcmp (*next_arg, "--version") == 0)
|
||||
{
|
||||
gdbserver_version ();
|
||||
exit (0);
|
||||
}
|
||||
else if (strcmp (*next_arg, "--help") == 0)
|
||||
{
|
||||
gdbserver_usage ();
|
||||
exit (0);
|
||||
}
|
||||
else if (strcmp (*next_arg, "--attach") == 0)
|
||||
attach = 1;
|
||||
else if (strcmp (*next_arg, "--multi") == 0)
|
||||
multi_mode = 1;
|
||||
else if (strcmp (*next_arg, "--debug") == 0)
|
||||
debug_threads = 1;
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Unknown argument: %s\n", *next_arg);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (argc >= 2 && strcmp (argv[1], "--help") == 0)
|
||||
{
|
||||
gdbserver_usage ();
|
||||
exit (0);
|
||||
next_arg++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setjmp (toplevel))
|
||||
@ -882,23 +1063,34 @@ main (int argc, char *argv[])
|
||||
exit (1);
|
||||
}
|
||||
|
||||
bad_attach = 0;
|
||||
pid = 0;
|
||||
attached = 0;
|
||||
if (argc >= 3 && strcmp (argv[2], "--attach") == 0)
|
||||
port = *next_arg;
|
||||
next_arg++;
|
||||
if (port == NULL || (!attach && !multi_mode && *next_arg == NULL))
|
||||
{
|
||||
if (argc == 4
|
||||
&& argv[3][0] != '\0'
|
||||
&& (pid = strtoul (argv[3], &arg_end, 0)) != 0
|
||||
&& *arg_end == '\0')
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
bad_attach = 1;
|
||||
gdbserver_usage ();
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (argc < 3 || bad_attach)
|
||||
bad_attach = 0;
|
||||
pid = 0;
|
||||
|
||||
/* --attach used to come after PORT, so allow it there for
|
||||
compatibility. */
|
||||
if (*next_arg != NULL && strcmp (*next_arg, "--attach") == 0)
|
||||
{
|
||||
attach = 1;
|
||||
next_arg++;
|
||||
}
|
||||
|
||||
if (attach
|
||||
&& (*next_arg == NULL
|
||||
|| (*next_arg)[0] == '\0'
|
||||
|| (pid = strtoul (*next_arg, &arg_end, 0)) == 0
|
||||
|| *arg_end != '\0'
|
||||
|| next_arg[1] != NULL))
|
||||
bad_attach = 1;
|
||||
|
||||
if (bad_attach)
|
||||
{
|
||||
gdbserver_usage ();
|
||||
exit (1);
|
||||
@ -910,26 +1102,34 @@ main (int argc, char *argv[])
|
||||
own_buf = malloc (PBUFSIZ + 1);
|
||||
mem_buf = malloc (PBUFSIZ);
|
||||
|
||||
if (pid == 0)
|
||||
if (pid == 0 && *next_arg != NULL)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
n = argc - (next_arg - argv);
|
||||
program_argv = malloc (sizeof (char *) * (n + 1));
|
||||
for (i = 0; i < n; i++)
|
||||
program_argv[i] = strdup (next_arg[i]);
|
||||
program_argv[i] = NULL;
|
||||
|
||||
/* Wait till we are at first instruction in program. */
|
||||
signal = start_inferior (&argv[2], &status);
|
||||
signal = start_inferior (program_argv, &status);
|
||||
|
||||
/* We are now (hopefully) stopped at the first instruction of
|
||||
the target process. This assumes that the target process was
|
||||
successfully created. */
|
||||
}
|
||||
else if (pid != 0)
|
||||
{
|
||||
if (attach_inferior (pid, &status, &signal) == -1)
|
||||
error ("Attaching not supported on this target");
|
||||
|
||||
/* Otherwise succeeded. */
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (attach_inferior (pid, &status, &signal))
|
||||
{
|
||||
case -1:
|
||||
error ("Attaching not supported on this target");
|
||||
break;
|
||||
default:
|
||||
attached = 1;
|
||||
break;
|
||||
}
|
||||
status = 'W';
|
||||
signal = 0;
|
||||
}
|
||||
|
||||
/* Don't report shared library events on the initial connection,
|
||||
@ -945,27 +1145,43 @@ main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (status == 'W' || status == 'X')
|
||||
was_running = 0;
|
||||
else
|
||||
was_running = 1;
|
||||
|
||||
if (!was_running && !multi_mode)
|
||||
{
|
||||
fprintf (stderr, "No inferior, GDBserver exiting.\n");
|
||||
fprintf (stderr, "No program to debug. GDBserver exiting.\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
remote_open (argv[1]);
|
||||
remote_open (port);
|
||||
|
||||
restart:
|
||||
setjmp (toplevel);
|
||||
if (setjmp (toplevel) != 0)
|
||||
{
|
||||
/* An error occurred. */
|
||||
if (response_needed)
|
||||
{
|
||||
write_enn (own_buf);
|
||||
putpkt (own_buf);
|
||||
}
|
||||
}
|
||||
|
||||
disable_async_io ();
|
||||
while (1)
|
||||
while (!exit_requested)
|
||||
{
|
||||
unsigned char sig;
|
||||
int packet_len;
|
||||
int new_packet_len = -1;
|
||||
|
||||
response_needed = 0;
|
||||
packet_len = getpkt (own_buf);
|
||||
if (packet_len <= 0)
|
||||
break;
|
||||
response_needed = 1;
|
||||
|
||||
i = 0;
|
||||
ch = own_buf[i++];
|
||||
@ -978,39 +1194,38 @@ main (int argc, char *argv[])
|
||||
handle_general_set (own_buf);
|
||||
break;
|
||||
case 'D':
|
||||
require_running (own_buf);
|
||||
fprintf (stderr, "Detaching from inferior\n");
|
||||
if (detach_inferior () != 0)
|
||||
{
|
||||
write_enn (own_buf);
|
||||
putpkt (own_buf);
|
||||
}
|
||||
write_enn (own_buf);
|
||||
else
|
||||
{
|
||||
write_ok (own_buf);
|
||||
putpkt (own_buf);
|
||||
remote_close ();
|
||||
|
||||
/* If we are attached, then we can exit. Otherwise, we
|
||||
need to hang around doing nothing, until the child
|
||||
is gone. */
|
||||
if (!attached)
|
||||
join_inferior ();
|
||||
if (extended_protocol)
|
||||
{
|
||||
/* Treat this like a normal program exit. */
|
||||
signal = 0;
|
||||
status = 'W';
|
||||
}
|
||||
else
|
||||
{
|
||||
putpkt (own_buf);
|
||||
remote_close ();
|
||||
|
||||
exit (0);
|
||||
/* If we are attached, then we can exit. Otherwise, we
|
||||
need to hang around doing nothing, until the child
|
||||
is gone. */
|
||||
if (!attached)
|
||||
join_inferior ();
|
||||
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
if (attached == 0)
|
||||
{
|
||||
extended_protocol = 1;
|
||||
prepare_resume_reply (own_buf, status, signal);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We can not use the extended protocol if we are
|
||||
attached, because we can not restart the running
|
||||
program. So return unrecognized. */
|
||||
own_buf[0] = '\0';
|
||||
}
|
||||
extended_protocol = 1;
|
||||
write_ok (own_buf);
|
||||
break;
|
||||
case '?':
|
||||
prepare_resume_reply (own_buf, status, signal);
|
||||
@ -1020,12 +1235,18 @@ main (int argc, char *argv[])
|
||||
{
|
||||
unsigned long gdb_id, thread_id;
|
||||
|
||||
require_running (own_buf);
|
||||
gdb_id = strtoul (&own_buf[2], NULL, 16);
|
||||
thread_id = gdb_id_to_thread_id (gdb_id);
|
||||
if (thread_id == 0)
|
||||
if (gdb_id == 0 || gdb_id == -1)
|
||||
thread_id = gdb_id;
|
||||
else
|
||||
{
|
||||
write_enn (own_buf);
|
||||
break;
|
||||
thread_id = gdb_id_to_thread_id (gdb_id);
|
||||
if (thread_id == 0)
|
||||
{
|
||||
write_enn (own_buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (own_buf[1] == 'g')
|
||||
@ -1048,15 +1269,18 @@ main (int argc, char *argv[])
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
require_running (own_buf);
|
||||
set_desired_inferior (1);
|
||||
registers_to_string (own_buf);
|
||||
break;
|
||||
case 'G':
|
||||
require_running (own_buf);
|
||||
set_desired_inferior (1);
|
||||
registers_from_string (&own_buf[1]);
|
||||
write_ok (own_buf);
|
||||
break;
|
||||
case 'm':
|
||||
require_running (own_buf);
|
||||
decode_m_packet (&own_buf[1], &mem_addr, &len);
|
||||
if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
|
||||
convert_int_to_ascii (mem_buf, own_buf, len);
|
||||
@ -1064,6 +1288,7 @@ main (int argc, char *argv[])
|
||||
write_enn (own_buf);
|
||||
break;
|
||||
case 'M':
|
||||
require_running (own_buf);
|
||||
decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
|
||||
if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
|
||||
write_ok (own_buf);
|
||||
@ -1071,6 +1296,7 @@ main (int argc, char *argv[])
|
||||
write_enn (own_buf);
|
||||
break;
|
||||
case 'X':
|
||||
require_running (own_buf);
|
||||
if (decode_X_packet (&own_buf[1], packet_len - 1,
|
||||
&mem_addr, &len, mem_buf) < 0
|
||||
|| write_inferior_memory (mem_addr, mem_buf, len) != 0)
|
||||
@ -1079,6 +1305,7 @@ main (int argc, char *argv[])
|
||||
write_ok (own_buf);
|
||||
break;
|
||||
case 'C':
|
||||
require_running (own_buf);
|
||||
convert_ascii_to_int (own_buf + 1, &sig, 1);
|
||||
if (target_signal_to_host_p (sig))
|
||||
signal = target_signal_to_host (sig);
|
||||
@ -1087,6 +1314,7 @@ main (int argc, char *argv[])
|
||||
myresume (own_buf, 0, &signal, &status);
|
||||
break;
|
||||
case 'S':
|
||||
require_running (own_buf);
|
||||
convert_ascii_to_int (own_buf + 1, &sig, 1);
|
||||
if (target_signal_to_host_p (sig))
|
||||
signal = target_signal_to_host (sig);
|
||||
@ -1095,10 +1323,12 @@ main (int argc, char *argv[])
|
||||
myresume (own_buf, 1, &signal, &status);
|
||||
break;
|
||||
case 'c':
|
||||
require_running (own_buf);
|
||||
signal = 0;
|
||||
myresume (own_buf, 0, &signal, &status);
|
||||
break;
|
||||
case 's':
|
||||
require_running (own_buf);
|
||||
signal = 0;
|
||||
myresume (own_buf, 1, &signal, &status);
|
||||
break;
|
||||
@ -1121,6 +1351,7 @@ main (int argc, char *argv[])
|
||||
{
|
||||
int res;
|
||||
|
||||
require_running (own_buf);
|
||||
res = (*the_target->insert_watchpoint) (type, addr, len);
|
||||
if (res == 0)
|
||||
write_ok (own_buf);
|
||||
@ -1151,6 +1382,7 @@ main (int argc, char *argv[])
|
||||
{
|
||||
int res;
|
||||
|
||||
require_running (own_buf);
|
||||
res = (*the_target->remove_watchpoint) (type, addr, len);
|
||||
if (res == 0)
|
||||
write_ok (own_buf);
|
||||
@ -1163,20 +1395,24 @@ main (int argc, char *argv[])
|
||||
break;
|
||||
}
|
||||
case 'k':
|
||||
response_needed = 0;
|
||||
if (!target_running ())
|
||||
/* The packet we received doesn't make sense - but we
|
||||
can't reply to it, either. */
|
||||
goto restart;
|
||||
|
||||
fprintf (stderr, "Killing inferior\n");
|
||||
kill_inferior ();
|
||||
/* When using the extended protocol, we start up a new
|
||||
debugging session. The traditional protocol will
|
||||
exit instead. */
|
||||
|
||||
/* When using the extended protocol, we wait with no
|
||||
program running. The traditional protocol will exit
|
||||
instead. */
|
||||
if (extended_protocol)
|
||||
{
|
||||
write_ok (own_buf);
|
||||
fprintf (stderr, "GDBserver restarting\n");
|
||||
|
||||
/* Wait till we are at 1st instruction in prog. */
|
||||
signal = start_inferior (&argv[2], &status);
|
||||
status = 'X';
|
||||
signal = TARGET_SIGNAL_KILL;
|
||||
was_running = 0;
|
||||
goto restart;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1187,6 +1423,7 @@ main (int argc, char *argv[])
|
||||
{
|
||||
unsigned long gdb_id, thread_id;
|
||||
|
||||
require_running (own_buf);
|
||||
gdb_id = strtoul (&own_buf[1], NULL, 16);
|
||||
thread_id = gdb_id_to_thread_id (gdb_id);
|
||||
if (thread_id == 0)
|
||||
@ -1202,18 +1439,25 @@ main (int argc, char *argv[])
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
response_needed = 0;
|
||||
|
||||
/* Restarting the inferior is only supported in the
|
||||
extended protocol. */
|
||||
if (extended_protocol)
|
||||
{
|
||||
kill_inferior ();
|
||||
write_ok (own_buf);
|
||||
if (target_running ())
|
||||
kill_inferior ();
|
||||
fprintf (stderr, "GDBserver restarting\n");
|
||||
|
||||
/* Wait till we are at 1st instruction in prog. */
|
||||
signal = start_inferior (&argv[2], &status);
|
||||
if (program_argv != NULL)
|
||||
signal = start_inferior (program_argv, &status);
|
||||
else
|
||||
{
|
||||
status = 'X';
|
||||
signal = TARGET_SIGNAL_KILL;
|
||||
}
|
||||
goto restart;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1242,45 +1486,45 @@ main (int argc, char *argv[])
|
||||
else
|
||||
putpkt (own_buf);
|
||||
|
||||
if (status == 'W')
|
||||
fprintf (stderr,
|
||||
"\nChild exited with status %d\n", signal);
|
||||
if (status == 'X')
|
||||
fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
|
||||
target_signal_to_host (signal),
|
||||
target_signal_to_name (signal));
|
||||
if (status == 'W' || status == 'X')
|
||||
{
|
||||
if (extended_protocol)
|
||||
{
|
||||
fprintf (stderr, "Killing inferior\n");
|
||||
kill_inferior ();
|
||||
write_ok (own_buf);
|
||||
fprintf (stderr, "GDBserver restarting\n");
|
||||
response_needed = 0;
|
||||
|
||||
/* Wait till we are at 1st instruction in prog. */
|
||||
signal = start_inferior (&argv[2], &status);
|
||||
goto restart;
|
||||
break;
|
||||
}
|
||||
if (was_running && (status == 'W' || status == 'X'))
|
||||
{
|
||||
was_running = 0;
|
||||
|
||||
if (status == 'W')
|
||||
fprintf (stderr,
|
||||
"\nChild exited with status %d\n", signal);
|
||||
if (status == 'X')
|
||||
fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
|
||||
target_signal_to_host (signal),
|
||||
target_signal_to_name (signal));
|
||||
|
||||
if (extended_protocol)
|
||||
goto restart;
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "GDBserver exiting\n");
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (status != 'W' && status != 'X')
|
||||
was_running = 1;
|
||||
}
|
||||
|
||||
/* We come here when getpkt fails.
|
||||
/* If an exit was requested (using the "monitor exit" command),
|
||||
terminate now. The only other way to get here is for
|
||||
getpkt to fail; close the connection and reopen it at the
|
||||
top of the loop. */
|
||||
|
||||
For the extended remote protocol we exit (and this is the only
|
||||
way we gracefully exit!).
|
||||
|
||||
For the traditional remote protocol close the connection,
|
||||
and re-open it at the top of the loop. */
|
||||
if (extended_protocol)
|
||||
if (exit_requested)
|
||||
{
|
||||
remote_close ();
|
||||
if (attached && target_running ())
|
||||
detach_inferior ();
|
||||
else if (target_running ())
|
||||
kill_inferior ();
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
|
529
gdb/remote.c
529
gdb/remote.c
@ -237,6 +237,15 @@ struct remote_state
|
||||
a buffer in the stub), this will be set to that packet size.
|
||||
Otherwise zero, meaning to use the guessed size. */
|
||||
long explicit_packet_size;
|
||||
|
||||
/* remote_wait is normally called when the target is running and
|
||||
waits for a stop reply packet. But sometimes we need to call it
|
||||
when the target is already stopped. We can send a "?" packet
|
||||
and have remote_wait read the response. Or, if we already have
|
||||
the response, we can stash it in BUF and tell remote_wait to
|
||||
skip calling getpkt. This flag is set when BUF contains a
|
||||
stop reply packet and the target is not waiting. */
|
||||
int cached_wait_status;
|
||||
};
|
||||
|
||||
/* This data could be associated with a target, but we do not always
|
||||
@ -514,6 +523,10 @@ static int remote_address_size;
|
||||
|
||||
static int remote_async_terminal_ours_p;
|
||||
|
||||
/* The executable file to use for "run" on the remote side. */
|
||||
|
||||
static char *remote_exec_file = "";
|
||||
|
||||
|
||||
/* User configurable variables for the number of characters in a
|
||||
memory read/write packet. MIN (rsa->remote_packet_size,
|
||||
@ -920,6 +933,8 @@ enum {
|
||||
PACKET_qGetTLSAddr,
|
||||
PACKET_qSupported,
|
||||
PACKET_QPassSignals,
|
||||
PACKET_vAttach,
|
||||
PACKET_vRun,
|
||||
PACKET_MAX
|
||||
};
|
||||
|
||||
@ -1993,11 +2008,6 @@ extended_remote_restart (void)
|
||||
putpkt (rs->buf);
|
||||
|
||||
remote_fileio_reset ();
|
||||
|
||||
/* Now query for status so this looks just like we restarted
|
||||
gdbserver from scratch. */
|
||||
putpkt ("?");
|
||||
getpkt (&rs->buf, &rs->buf_size, 0);
|
||||
}
|
||||
|
||||
/* Clean up connection to a remote debugger. */
|
||||
@ -2159,27 +2169,79 @@ get_offsets (void)
|
||||
|
||||
/* Stub for catch_exception. */
|
||||
|
||||
static void
|
||||
remote_start_remote (struct ui_out *uiout, void *from_tty_p)
|
||||
struct start_remote_args
|
||||
{
|
||||
int from_tty = * (int *) from_tty_p;
|
||||
int from_tty;
|
||||
|
||||
/* The current target. */
|
||||
struct target_ops *target;
|
||||
|
||||
/* Non-zero if this is an extended-remote target. */
|
||||
int extended_p;
|
||||
};
|
||||
|
||||
static void
|
||||
remote_start_remote (struct ui_out *uiout, void *opaque)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
struct start_remote_args *args = opaque;
|
||||
char *wait_status = NULL;
|
||||
|
||||
immediate_quit++; /* Allow user to interrupt it. */
|
||||
|
||||
/* Ack any packet which the remote side has already sent. */
|
||||
serial_write (remote_desc, "+", 1);
|
||||
|
||||
/* Check whether the target is running now. */
|
||||
putpkt ("?");
|
||||
getpkt (&rs->buf, &rs->buf_size, 0);
|
||||
|
||||
if (rs->buf[0] == 'W' || rs->buf[0] == 'X')
|
||||
{
|
||||
if (args->extended_p)
|
||||
{
|
||||
/* We're connected, but not running. Drop out before we
|
||||
call start_remote. */
|
||||
target_mark_exited (args->target);
|
||||
return;
|
||||
}
|
||||
else
|
||||
error (_("The target is not running (try extended-remote?)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (args->extended_p)
|
||||
target_mark_running (args->target);
|
||||
|
||||
/* Save the reply for later. */
|
||||
wait_status = alloca (strlen (rs->buf) + 1);
|
||||
strcpy (wait_status, rs->buf);
|
||||
}
|
||||
|
||||
/* Let the stub know that we want it to return the thread. */
|
||||
set_thread (-1, 0);
|
||||
|
||||
/* Without this, some commands which require an active target
|
||||
(such as kill) won't work. This variable serves (at least)
|
||||
double duty as both the pid of the target process (if it has
|
||||
such), and as a flag indicating that a target is active.
|
||||
These functions should be split out into seperate variables,
|
||||
especially since GDB will someday have a notion of debugging
|
||||
several processes. */
|
||||
inferior_ptid = pid_to_ptid (MAGIC_NULL_PID);
|
||||
|
||||
/* Now, if we have thread information, update inferior_ptid. */
|
||||
inferior_ptid = remote_current_thread (inferior_ptid);
|
||||
|
||||
get_offsets (); /* Get text, data & bss offsets. */
|
||||
|
||||
putpkt ("?"); /* Initiate a query from remote machine. */
|
||||
immediate_quit--;
|
||||
/* Use the previously fetched status. */
|
||||
gdb_assert (wait_status != NULL);
|
||||
strcpy (rs->buf, wait_status);
|
||||
rs->cached_wait_status = 1;
|
||||
|
||||
start_remote (from_tty); /* Initialize gdb process mechanisms. */
|
||||
immediate_quit--;
|
||||
start_remote (args->from_tty); /* Initialize gdb process mechanisms. */
|
||||
}
|
||||
|
||||
/* Open a connection to a remote debugger.
|
||||
@ -2540,10 +2602,31 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target,
|
||||
if (!async_p)
|
||||
wait_forever_enabled_p = 1;
|
||||
|
||||
/* If we're connected to a running target, target_preopen will kill it.
|
||||
But if we're connected to a target system with no running process,
|
||||
then we will still be connected when it returns. Ask this question
|
||||
first, before target_preopen has a chance to kill anything. */
|
||||
if (remote_desc != NULL && !target_has_execution)
|
||||
{
|
||||
if (!from_tty
|
||||
|| query (_("Already connected to a remote target. Disconnect? ")))
|
||||
pop_target ();
|
||||
else
|
||||
error (_("Still connected."));
|
||||
}
|
||||
|
||||
target_preopen (from_tty);
|
||||
|
||||
unpush_target (target);
|
||||
|
||||
/* This time without a query. If we were connected to an
|
||||
extended-remote target and target_preopen killed the running
|
||||
process, we may still be connected. If we are starting "target
|
||||
remote" now, the extended-remote target will not have been
|
||||
removed by unpush_target. */
|
||||
if (remote_desc != NULL && !target_has_execution)
|
||||
pop_target ();
|
||||
|
||||
/* Make sure we send the passed signals list the next time we resume. */
|
||||
xfree (last_pass_packet);
|
||||
last_pass_packet = NULL;
|
||||
@ -2584,6 +2667,9 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target,
|
||||
}
|
||||
push_target (target); /* Switch to using remote target now. */
|
||||
|
||||
/* Assume that the target is running, unless we learn otherwise. */
|
||||
target_mark_running (target);
|
||||
|
||||
/* Reset the target state; these things will be queried either by
|
||||
remote_query_supported or as they are needed. */
|
||||
init_all_packet_configs ();
|
||||
@ -2605,15 +2691,6 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target,
|
||||
this before anything involving memory or registers. */
|
||||
target_find_description ();
|
||||
|
||||
/* Without this, some commands which require an active target (such
|
||||
as kill) won't work. This variable serves (at least) double duty
|
||||
as both the pid of the target process (if it has such), and as a
|
||||
flag indicating that a target is active. These functions should
|
||||
be split out into seperate variables, especially since GDB will
|
||||
someday have a notion of debugging several processes. */
|
||||
|
||||
inferior_ptid = pid_to_ptid (MAGIC_NULL_PID);
|
||||
|
||||
if (async_p)
|
||||
{
|
||||
/* With this target we start out by owning the terminal. */
|
||||
@ -2648,9 +2725,14 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target,
|
||||
all the ``target ....'' commands to share a common callback
|
||||
function. See cli-dump.c. */
|
||||
{
|
||||
struct gdb_exception ex
|
||||
= catch_exception (uiout, remote_start_remote, &from_tty,
|
||||
RETURN_MASK_ALL);
|
||||
struct gdb_exception ex;
|
||||
struct start_remote_args args;
|
||||
|
||||
args.from_tty = from_tty;
|
||||
args.target = target;
|
||||
args.extended_p = extended_p;
|
||||
|
||||
ex = catch_exception (uiout, remote_start_remote, &args, RETURN_MASK_ALL);
|
||||
if (ex.reason < 0)
|
||||
{
|
||||
pop_target ();
|
||||
@ -2670,8 +2752,12 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target,
|
||||
getpkt (&rs->buf, &rs->buf_size, 0);
|
||||
}
|
||||
|
||||
if (exec_bfd) /* No use without an exec file. */
|
||||
remote_check_symbols (symfile_objfile);
|
||||
/* If we connected to a live target, do some additional setup. */
|
||||
if (target_has_execution)
|
||||
{
|
||||
if (exec_bfd) /* No use without an exec file. */
|
||||
remote_check_symbols (symfile_objfile);
|
||||
}
|
||||
}
|
||||
|
||||
/* This takes a program previously attached to and detaches it. After
|
||||
@ -2680,13 +2766,16 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target,
|
||||
die when it hits one. */
|
||||
|
||||
static void
|
||||
remote_detach (char *args, int from_tty)
|
||||
remote_detach_1 (char *args, int from_tty, int extended)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
|
||||
if (args)
|
||||
error (_("Argument given to \"detach\" when remotely debugging."));
|
||||
|
||||
if (!target_has_execution)
|
||||
error (_("No process to detach from."));
|
||||
|
||||
/* Tell the remote target to detach. */
|
||||
strcpy (rs->buf, "D");
|
||||
putpkt (rs->buf);
|
||||
@ -2701,7 +2790,24 @@ remote_detach (char *args, int from_tty)
|
||||
|
||||
target_mourn_inferior ();
|
||||
if (from_tty)
|
||||
puts_filtered ("Ending remote debugging.\n");
|
||||
{
|
||||
if (extended)
|
||||
puts_filtered ("Detached from remote process.\n");
|
||||
else
|
||||
puts_filtered ("Ending remote debugging.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
remote_detach (char *args, int from_tty)
|
||||
{
|
||||
remote_detach_1 (args, from_tty, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
extended_remote_detach (char *args, int from_tty)
|
||||
{
|
||||
remote_detach_1 (args, from_tty, 1);
|
||||
}
|
||||
|
||||
/* Same as remote_detach, but don't send the "D" packet; just disconnect. */
|
||||
@ -2710,17 +2816,78 @@ static void
|
||||
remote_disconnect (struct target_ops *target, char *args, int from_tty)
|
||||
{
|
||||
if (args)
|
||||
error (_("Argument given to \"detach\" when remotely debugging."));
|
||||
error (_("Argument given to \"disconnect\" when remotely debugging."));
|
||||
|
||||
/* Unregister the file descriptor from the event loop. */
|
||||
if (target_is_async_p ())
|
||||
serial_async (remote_desc, NULL, 0);
|
||||
|
||||
target_mourn_inferior ();
|
||||
/* Make sure we unpush even the extended remote targets; mourn
|
||||
won't do it. So call remote_mourn_1 directly instead of
|
||||
target_mourn_inferior. */
|
||||
remote_mourn_1 (target);
|
||||
|
||||
if (from_tty)
|
||||
puts_filtered ("Ending remote debugging.\n");
|
||||
}
|
||||
|
||||
/* Attach to the process specified by ARGS. If FROM_TTY is non-zero,
|
||||
be chatty about it. */
|
||||
|
||||
static void
|
||||
extended_remote_attach_1 (struct target_ops *target, char *args, int from_tty)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
pid_t pid;
|
||||
char *dummy;
|
||||
|
||||
if (!args)
|
||||
error_no_arg (_("process-id to attach"));
|
||||
|
||||
dummy = args;
|
||||
pid = strtol (args, &dummy, 0);
|
||||
/* Some targets don't set errno on errors, grrr! */
|
||||
if (pid == 0 && args == dummy)
|
||||
error (_("Illegal process-id: %s."), args);
|
||||
|
||||
if (remote_protocol_packets[PACKET_vAttach].support == PACKET_DISABLE)
|
||||
error (_("This target does not support attaching to a process"));
|
||||
|
||||
sprintf (rs->buf, "vAttach;%x", pid);
|
||||
putpkt (rs->buf);
|
||||
getpkt (&rs->buf, &rs->buf_size, 0);
|
||||
|
||||
if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vAttach]) == PACKET_OK)
|
||||
{
|
||||
if (from_tty)
|
||||
printf_unfiltered (_("Attached to %s\n"),
|
||||
target_pid_to_str (pid_to_ptid (pid)));
|
||||
|
||||
/* We have a wait response; reuse it. */
|
||||
rs->cached_wait_status = 1;
|
||||
}
|
||||
else if (remote_protocol_packets[PACKET_vAttach].support == PACKET_DISABLE)
|
||||
error (_("This target does not support attaching to a process"));
|
||||
else
|
||||
error (_("Attaching to %s failed"),
|
||||
target_pid_to_str (pid_to_ptid (pid)));
|
||||
|
||||
target_mark_running (target);
|
||||
inferior_ptid = pid_to_ptid (pid);
|
||||
}
|
||||
|
||||
static void
|
||||
extended_remote_attach (char *args, int from_tty)
|
||||
{
|
||||
extended_remote_attach_1 (&extended_remote_ops, args, from_tty);
|
||||
}
|
||||
|
||||
static void
|
||||
extended_async_remote_attach (char *args, int from_tty)
|
||||
{
|
||||
extended_remote_attach_1 (&extended_async_remote_ops, args, from_tty);
|
||||
}
|
||||
|
||||
/* Convert hex digit A to a number. */
|
||||
|
||||
static int
|
||||
@ -2845,7 +3012,7 @@ remote_vcont_resume (ptid_t ptid, int step, enum target_signal siggnal)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
int pid = PIDGET (ptid);
|
||||
char *buf = NULL, *outbuf;
|
||||
char *outbuf;
|
||||
struct cleanup *old_cleanup;
|
||||
|
||||
if (remote_protocol_packets[PACKET_vCont].support == PACKET_SUPPORT_UNKNOWN)
|
||||
@ -3203,16 +3370,22 @@ remote_wait (ptid_t ptid, struct target_waitstatus *status)
|
||||
{
|
||||
char *buf, *p;
|
||||
|
||||
ofunc = signal (SIGINT, remote_interrupt);
|
||||
/* If the user hit C-c before this packet, or between packets,
|
||||
pretend that it was hit right here. */
|
||||
if (quit_flag)
|
||||
if (rs->cached_wait_status)
|
||||
/* Use the cached wait status, but only once. */
|
||||
rs->cached_wait_status = 0;
|
||||
else
|
||||
{
|
||||
quit_flag = 0;
|
||||
remote_interrupt (SIGINT);
|
||||
ofunc = signal (SIGINT, remote_interrupt);
|
||||
/* If the user hit C-c before this packet, or between packets,
|
||||
pretend that it was hit right here. */
|
||||
if (quit_flag)
|
||||
{
|
||||
quit_flag = 0;
|
||||
remote_interrupt (SIGINT);
|
||||
}
|
||||
getpkt (&rs->buf, &rs->buf_size, 1);
|
||||
signal (SIGINT, ofunc);
|
||||
}
|
||||
getpkt (&rs->buf, &rs->buf_size, 1);
|
||||
signal (SIGINT, ofunc);
|
||||
|
||||
buf = rs->buf;
|
||||
|
||||
@ -3419,24 +3592,30 @@ remote_async_wait (ptid_t ptid, struct target_waitstatus *status)
|
||||
{
|
||||
char *buf, *p;
|
||||
|
||||
if (!target_is_async_p ())
|
||||
if (rs->cached_wait_status)
|
||||
/* Use the cached wait status, but only once. */
|
||||
rs->cached_wait_status = 0;
|
||||
else
|
||||
{
|
||||
ofunc = signal (SIGINT, remote_interrupt);
|
||||
/* If the user hit C-c before this packet, or between packets,
|
||||
pretend that it was hit right here. */
|
||||
if (quit_flag)
|
||||
if (!target_is_async_p ())
|
||||
{
|
||||
quit_flag = 0;
|
||||
remote_interrupt (SIGINT);
|
||||
ofunc = signal (SIGINT, remote_interrupt);
|
||||
/* If the user hit C-c before this packet, or between packets,
|
||||
pretend that it was hit right here. */
|
||||
if (quit_flag)
|
||||
{
|
||||
quit_flag = 0;
|
||||
remote_interrupt (SIGINT);
|
||||
}
|
||||
}
|
||||
/* FIXME: cagney/1999-09-27: If we're in async mode we should
|
||||
_never_ wait for ever -> test on target_is_async_p().
|
||||
However, before we do that we need to ensure that the caller
|
||||
knows how to take the target into/out of async mode. */
|
||||
getpkt (&rs->buf, &rs->buf_size, wait_forever_enabled_p);
|
||||
if (!target_is_async_p ())
|
||||
signal (SIGINT, ofunc);
|
||||
}
|
||||
/* FIXME: cagney/1999-09-27: If we're in async mode we should
|
||||
_never_ wait for ever -> test on target_is_async_p().
|
||||
However, before we do that we need to ensure that the caller
|
||||
knows how to take the target into/out of async mode. */
|
||||
getpkt (&rs->buf, &rs->buf_size, wait_forever_enabled_p);
|
||||
if (!target_is_async_p ())
|
||||
signal (SIGINT, ofunc);
|
||||
|
||||
buf = rs->buf;
|
||||
|
||||
@ -4705,6 +4884,7 @@ putpkt (char *buf)
|
||||
static int
|
||||
putpkt_binary (char *buf, int cnt)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
int i;
|
||||
unsigned char csum = 0;
|
||||
char *buf2 = alloca (cnt + 6);
|
||||
@ -4713,6 +4893,10 @@ putpkt_binary (char *buf, int cnt)
|
||||
int tcount = 0;
|
||||
char *p;
|
||||
|
||||
/* We're sending out a new packet. Make sure we don't look at a
|
||||
stale cached response. */
|
||||
rs->cached_wait_status = 0;
|
||||
|
||||
/* Copy the packet into buffer BUF2, encapsulating it
|
||||
and giving it a checksum. */
|
||||
|
||||
@ -5014,11 +5198,16 @@ getpkt (char **buf,
|
||||
static int
|
||||
getpkt_sane (char **buf, long *sizeof_buf, int forever)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
int c;
|
||||
int tries;
|
||||
int timeout;
|
||||
int val;
|
||||
|
||||
/* We're reading a new response. Make sure we don't look at a
|
||||
previously cached response. */
|
||||
rs->cached_wait_status = 0;
|
||||
|
||||
strcpy (*buf, "timeout");
|
||||
|
||||
if (forever)
|
||||
@ -5150,19 +5339,6 @@ remote_async_mourn (void)
|
||||
remote_mourn_1 (&remote_async_ops);
|
||||
}
|
||||
|
||||
static void
|
||||
extended_remote_mourn (void)
|
||||
{
|
||||
/* We do _not_ want to mourn the target like this; this will
|
||||
remove the extended remote target from the target stack,
|
||||
and the next time the user says "run" it'll fail.
|
||||
|
||||
FIXME: What is the right thing to do here? */
|
||||
#if 0
|
||||
remote_mourn_1 (&extended_remote_ops);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Worker function for remote_mourn. */
|
||||
static void
|
||||
remote_mourn_1 (struct target_ops *target)
|
||||
@ -5171,71 +5347,167 @@ remote_mourn_1 (struct target_ops *target)
|
||||
generic_mourn_inferior ();
|
||||
}
|
||||
|
||||
static void
|
||||
extended_remote_mourn_1 (struct target_ops *target)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
|
||||
/* Unlike "target remote", we do not want to unpush the target; then
|
||||
the next time the user says "run", we won't be connected. */
|
||||
|
||||
/* Call common code to mark the inferior as not running. */
|
||||
generic_mourn_inferior ();
|
||||
|
||||
/* Check whether the target is running now - some remote stubs
|
||||
automatically restart after kill. */
|
||||
putpkt ("?");
|
||||
getpkt (&rs->buf, &rs->buf_size, 0);
|
||||
|
||||
if (rs->buf[0] == 'S' || rs->buf[0] == 'T')
|
||||
{
|
||||
/* Assume that the target has been restarted. Set inferior_ptid
|
||||
so that bits of core GDB realizes there's something here, e.g.,
|
||||
so that the user can say "kill" again. */
|
||||
inferior_ptid = pid_to_ptid (MAGIC_NULL_PID);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Mark this (still pushed) target as not executable until we
|
||||
restart it. */
|
||||
target_mark_exited (target);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
extended_remote_mourn (void)
|
||||
{
|
||||
extended_remote_mourn_1 (&extended_remote_ops);
|
||||
}
|
||||
|
||||
static void
|
||||
extended_async_remote_mourn (void)
|
||||
{
|
||||
extended_remote_mourn_1 (&extended_async_remote_ops);
|
||||
}
|
||||
|
||||
static int
|
||||
extended_remote_run (char *args)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
char *p;
|
||||
int len;
|
||||
|
||||
/* If the user has disabled vRun support, or we have detected that
|
||||
support is not available, do not try it. */
|
||||
if (remote_protocol_packets[PACKET_vRun].support == PACKET_DISABLE)
|
||||
return -1;
|
||||
|
||||
strcpy (rs->buf, "vRun;");
|
||||
len = strlen (rs->buf);
|
||||
|
||||
if (strlen (remote_exec_file) * 2 + len >= get_remote_packet_size ())
|
||||
error (_("Remote file name too long for run packet"));
|
||||
len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len, 0);
|
||||
|
||||
if (*args)
|
||||
{
|
||||
struct cleanup *back_to;
|
||||
int i;
|
||||
char **argv;
|
||||
|
||||
argv = buildargv (args);
|
||||
back_to = make_cleanup ((void (*) (void *)) freeargv, argv);
|
||||
for (i = 0; argv[i] != NULL; i++)
|
||||
{
|
||||
if (strlen (argv[i]) * 2 + 1 + len >= get_remote_packet_size ())
|
||||
error (_("Argument list too long for run packet"));
|
||||
rs->buf[len++] = ';';
|
||||
len += 2 * bin2hex ((gdb_byte *) argv[i], rs->buf + len, 0);
|
||||
}
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
rs->buf[len++] = '\0';
|
||||
|
||||
putpkt (rs->buf);
|
||||
getpkt (&rs->buf, &rs->buf_size, 0);
|
||||
|
||||
if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vRun]) == PACKET_OK)
|
||||
{
|
||||
/* We have a wait response; we don't need it, though. All is well. */
|
||||
return 0;
|
||||
}
|
||||
else if (remote_protocol_packets[PACKET_vRun].support == PACKET_DISABLE)
|
||||
/* It wasn't disabled before, but it is now. */
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
if (remote_exec_file[0] == '\0')
|
||||
error (_("Running the default executable on the remote target failed; "
|
||||
"try \"set remote exec-file\"?"));
|
||||
else
|
||||
error (_("Running \"%s\" on the remote target failed"),
|
||||
remote_exec_file);
|
||||
}
|
||||
}
|
||||
|
||||
/* In the extended protocol we want to be able to do things like
|
||||
"run" and have them basically work as expected. So we need
|
||||
a special create_inferior function.
|
||||
a special create_inferior function. We support changing the
|
||||
executable file and the command line arguments, but not the
|
||||
environment. */
|
||||
|
||||
FIXME: One day add support for changing the exec file
|
||||
we're debugging, arguments and an environment. */
|
||||
static void
|
||||
extended_remote_create_inferior_1 (char *exec_file, char *args,
|
||||
char **env, int from_tty,
|
||||
int async_p)
|
||||
{
|
||||
/* If running asynchronously, register the target file descriptor
|
||||
with the event loop. */
|
||||
if (async_p && target_can_async_p ())
|
||||
target_async (inferior_event_handler, 0);
|
||||
|
||||
/* Now restart the remote server. */
|
||||
if (extended_remote_run (args) == -1)
|
||||
{
|
||||
/* vRun was not supported. Fail if we need it to do what the
|
||||
user requested. */
|
||||
if (remote_exec_file[0])
|
||||
error (_("Remote target does not support \"set remote exec-file\""));
|
||||
if (args[0])
|
||||
error (_("Remote target does not support \"set args\" or run <ARGS>"));
|
||||
|
||||
/* Fall back to "R". */
|
||||
extended_remote_restart ();
|
||||
}
|
||||
|
||||
/* Now mark the inferior as running before we do anything else. */
|
||||
inferior_ptid = pid_to_ptid (MAGIC_NULL_PID);
|
||||
if (async_p)
|
||||
target_mark_running (&extended_async_remote_ops);
|
||||
else
|
||||
target_mark_running (&extended_remote_ops);
|
||||
|
||||
/* Get updated offsets, if the stub uses qOffsets. */
|
||||
get_offsets ();
|
||||
|
||||
/* Clean up from the last time we were running. */
|
||||
init_thread_list ();
|
||||
init_wait_for_inferior ();
|
||||
}
|
||||
|
||||
static void
|
||||
extended_remote_create_inferior (char *exec_file, char *args,
|
||||
char **env, int from_tty)
|
||||
{
|
||||
/* Rip out the breakpoints; we'll reinsert them after restarting
|
||||
the remote server. */
|
||||
remove_breakpoints ();
|
||||
|
||||
/* Now restart the remote server. */
|
||||
extended_remote_restart ();
|
||||
|
||||
/* NOTE: We don't need to recheck for a target description here; but
|
||||
if we gain the ability to switch the remote executable we may
|
||||
need to, if for instance we are running a process which requested
|
||||
different emulated hardware from the operating system. A
|
||||
concrete example of this is ARM GNU/Linux, where some binaries
|
||||
will have a legacy FPA coprocessor emulated and others may have
|
||||
access to a hardware VFP unit. */
|
||||
|
||||
/* Now put the breakpoints back in. This way we're safe if the
|
||||
restart function works via a unix fork on the remote side. */
|
||||
insert_breakpoints ();
|
||||
|
||||
/* Clean up from the last time we were running. */
|
||||
clear_proceed_status ();
|
||||
extended_remote_create_inferior_1 (exec_file, args, env, from_tty, 0);
|
||||
}
|
||||
|
||||
/* Async version of extended_remote_create_inferior. */
|
||||
static void
|
||||
extended_remote_async_create_inferior (char *exec_file, char *args,
|
||||
char **env, int from_tty)
|
||||
{
|
||||
/* Rip out the breakpoints; we'll reinsert them after restarting
|
||||
the remote server. */
|
||||
remove_breakpoints ();
|
||||
|
||||
/* If running asynchronously, register the target file descriptor
|
||||
with the event loop. */
|
||||
if (target_can_async_p ())
|
||||
target_async (inferior_event_handler, 0);
|
||||
|
||||
/* Now restart the remote server. */
|
||||
extended_remote_restart ();
|
||||
|
||||
/* NOTE: We don't need to recheck for a target description here; but
|
||||
if we gain the ability to switch the remote executable we may
|
||||
need to, if for instance we are running a process which requested
|
||||
different emulated hardware from the operating system. A
|
||||
concrete example of this is ARM GNU/Linux, where some binaries
|
||||
will have a legacy FPA coprocessor emulated and others may have
|
||||
access to a hardware VFP unit. */
|
||||
|
||||
/* Now put the breakpoints back in. This way we're safe if the
|
||||
restart function works via a unix fork on the remote side. */
|
||||
insert_breakpoints ();
|
||||
|
||||
/* Clean up from the last time we were running. */
|
||||
clear_proceed_status ();
|
||||
extended_remote_create_inferior_1 (exec_file, args, env, from_tty, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -5793,6 +6065,12 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
int xfered;
|
||||
errno = 0;
|
||||
|
||||
/* If the remote target is connected but not running, we should
|
||||
pass this request down to a lower stratum (e.g. the executable
|
||||
file). */
|
||||
if (!target_has_execution)
|
||||
return 0;
|
||||
|
||||
if (writebuf != NULL)
|
||||
xfered = remote_write_bytes (offset, writebuf, len);
|
||||
else
|
||||
@ -6994,6 +7272,8 @@ Specify the serial device it is connected to (e.g. /dev/ttya).",
|
||||
extended_remote_ops.to_open = extended_remote_open;
|
||||
extended_remote_ops.to_create_inferior = extended_remote_create_inferior;
|
||||
extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
|
||||
extended_remote_ops.to_detach = extended_remote_detach;
|
||||
extended_remote_ops.to_attach = extended_remote_attach;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -7126,7 +7406,9 @@ init_extended_async_remote_ops (void)
|
||||
Specify the serial device it is connected to (e.g. /dev/ttya).",
|
||||
extended_async_remote_ops.to_open = extended_remote_async_open;
|
||||
extended_async_remote_ops.to_create_inferior = extended_remote_async_create_inferior;
|
||||
extended_async_remote_ops.to_mourn_inferior = extended_remote_mourn;
|
||||
extended_async_remote_ops.to_mourn_inferior = extended_async_remote_mourn;
|
||||
extended_async_remote_ops.to_detach = extended_remote_detach;
|
||||
extended_async_remote_ops.to_attach = extended_async_remote_attach;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -7381,6 +7663,12 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_unlink],
|
||||
"vFile:unlink", "hostio-unlink", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_vAttach],
|
||||
"vAttach", "attach", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_vRun],
|
||||
"vRun", "run", 0);
|
||||
|
||||
/* Keep the old ``set remote Z-packet ...'' working. Each individual
|
||||
Z sub-packet has its own set and show commands, but users may
|
||||
have sets to this variable in their .gdbinit files (or in their
|
||||
@ -7413,6 +7701,13 @@ Transfer files to and from the remote target system."),
|
||||
_("Delete a remote file."),
|
||||
&remote_cmdlist);
|
||||
|
||||
remote_exec_file = xstrdup ("");
|
||||
add_setshow_string_noescape_cmd ("exec-file", class_files,
|
||||
&remote_exec_file, _("\
|
||||
Set the remote pathname for \"run\""), _("\
|
||||
Show the remote pathname for \"run\""), NULL, NULL, NULL,
|
||||
&remote_set_cmdlist, &remote_show_cmdlist);
|
||||
|
||||
/* Eventually initialize fileio. See fileio.c */
|
||||
initialize_remote_fileio (remote_set_cmdlist, remote_show_cmdlist);
|
||||
}
|
||||
|
@ -1,3 +1,13 @@
|
||||
2008-01-29 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.server/ext-attach.c, gdb.server/ext-attach.exp,
|
||||
gdb.server/ext-run.exp: New files.
|
||||
* lib/gdbserver-support.exp (gdbserver_download): New.
|
||||
(gdbserver_start): New. Update gdbserver expected
|
||||
output.
|
||||
(gdbserver_spawn): Use them.
|
||||
(gdbserver_start_extended): New.
|
||||
|
||||
2008-01-29 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.base/foll-exec.exp: Update header. Skip on remote targets.
|
||||
|
31
gdb/testsuite/gdb.server/ext-attach.c
Normal file
31
gdb/testsuite/gdb.server/ext-attach.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2007 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This program is intended to be started outside of gdb, and then
|
||||
attached to by gdb. It loops for a while, but not forever. */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
int main ()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 120; i++)
|
||||
sleep (1);
|
||||
|
||||
return 0;
|
||||
}
|
77
gdb/testsuite/gdb.server/ext-attach.exp
Normal file
77
gdb/testsuite/gdb.server/ext-attach.exp
Normal file
@ -0,0 +1,77 @@
|
||||
# This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
# Copyright 2007 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Test attaching to already-running programs using extended-remote.
|
||||
|
||||
load_lib gdbserver-support.exp
|
||||
|
||||
set testfile "ext-attach"
|
||||
set srcfile ${testfile}.c
|
||||
set binfile ${objdir}/${subdir}/${testfile}
|
||||
|
||||
if { [skip_gdbserver_tests] } {
|
||||
return 0
|
||||
}
|
||||
|
||||
# On SPU, this test currently fails because "sleep" is not supported.
|
||||
if { [istarget "spu*-*-*"] } {
|
||||
return 0
|
||||
}
|
||||
|
||||
# We need to use TCL's exec to get the pid.
|
||||
if [is_remote target] then {
|
||||
return 0
|
||||
}
|
||||
|
||||
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
|
||||
untested ext-attach.exp
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_exit
|
||||
gdb_start
|
||||
gdb_load $binfile
|
||||
gdb_reinitialize_dir $srcdir/$subdir
|
||||
|
||||
set target_exec [gdbserver_download]
|
||||
gdbserver_start_extended
|
||||
|
||||
gdb_test "set remote exec-file $target_exec" "" "set remote exec-file"
|
||||
|
||||
# Start the program running and then wait for a bit, to be sure
|
||||
# that it can be attached to.
|
||||
set testpid [eval exec $binfile &]
|
||||
exec sleep 2
|
||||
if { [istarget "*-*-cygwin*"] } {
|
||||
# testpid is the Cygwin PID, GDB uses the Windows PID, which might be
|
||||
# different due to the way fork/exec works.
|
||||
set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ]
|
||||
}
|
||||
|
||||
gdb_test "attach $testpid" "Attached to.*" \
|
||||
"attach to remote program 1"
|
||||
gdb_test "backtrace" ".*main.*" "backtrace 1"
|
||||
|
||||
gdb_test "detach" "Detached from remote process\\."
|
||||
gdb_test "backtrace" "No stack\\." "backtrace with no program"
|
||||
|
||||
gdb_test "attach $testpid" "Attached to.*" \
|
||||
"attach to remote program 2"
|
||||
gdb_test "backtrace" ".*main.*" "backtrace 2"
|
||||
|
||||
gdb_test "kill" "" "kill" "Kill the program being debugged.*" "y"
|
||||
gdb_test "monitor exit" ""
|
48
gdb/testsuite/gdb.server/ext-run.exp
Normal file
48
gdb/testsuite/gdb.server/ext-run.exp
Normal file
@ -0,0 +1,48 @@
|
||||
# This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
# Copyright 2007 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Test running programs using extended-remote.
|
||||
|
||||
load_lib gdbserver-support.exp
|
||||
|
||||
set testfile "server"
|
||||
set srcfile ${testfile}.c
|
||||
set binfile ${objdir}/${subdir}/${testfile}
|
||||
|
||||
if { [skip_gdbserver_tests] } {
|
||||
return 0
|
||||
}
|
||||
|
||||
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_exit
|
||||
gdb_start
|
||||
gdb_load $binfile
|
||||
gdb_reinitialize_dir $srcdir/$subdir
|
||||
|
||||
set target_exec [gdbserver_download]
|
||||
gdbserver_start_extended
|
||||
|
||||
gdb_test "set remote exec-file $target_exec" "" "set remote exec-file"
|
||||
|
||||
gdb_breakpoint main
|
||||
gdb_test "run" "Breakpoint.* main .*" "continue to main"
|
||||
|
||||
gdb_test "kill" "" "kill" "Kill the program being debugged.*" "y"
|
||||
gdb_test "monitor exit" ""
|
@ -132,13 +132,10 @@ proc skip_gdbserver_tests { } {
|
||||
return 0
|
||||
}
|
||||
|
||||
# Start a gdbserver process running SERVER_EXEC, and connect GDB
|
||||
# to it. CHILD_ARGS are passed to the inferior.
|
||||
#
|
||||
# Returns the target protocol and socket to connect to.
|
||||
# Download the currently loaded program to the target if necessary.
|
||||
# Return the target system filename.
|
||||
|
||||
proc gdbserver_spawn { child_args } {
|
||||
global portnum
|
||||
proc gdbserver_download { } {
|
||||
global gdbserver_host_exec
|
||||
global gdbserver_host_mtime
|
||||
global gdbserver_server_exec
|
||||
@ -172,6 +169,17 @@ proc gdbserver_spawn { child_args } {
|
||||
}
|
||||
}
|
||||
|
||||
return $gdbserver_server_exec
|
||||
}
|
||||
|
||||
# Start a gdbserver process with initial OPTIONS and trailing ARGUMENTS.
|
||||
# The port will be filled in between them automatically.
|
||||
#
|
||||
# Returns the target protocol and socket to connect to.
|
||||
|
||||
proc gdbserver_start { options arguments } {
|
||||
global portnum
|
||||
|
||||
# Port id -- either specified in baseboard file, or managed here.
|
||||
if [target_info exists gdb,socketport] {
|
||||
set portnum [target_info gdb,socketport]
|
||||
@ -182,7 +190,7 @@ proc gdbserver_spawn { child_args } {
|
||||
|
||||
# Extract the local and remote host ids from the target board struct.
|
||||
if [target_info exists sockethost] {
|
||||
set debughost [target_info sockethost]
|
||||
set debughost [target_info sockethost]
|
||||
} else {
|
||||
set debughost "localhost:"
|
||||
}
|
||||
@ -199,23 +207,23 @@ proc gdbserver_spawn { child_args } {
|
||||
# Export the host:port pair.
|
||||
set gdbport $debughost$portnum
|
||||
|
||||
# Fire off the debug agent. This flavour of gdbserver takes as
|
||||
# arguments the port information, the name of the executable file to
|
||||
# be debugged, and any arguments.
|
||||
set gdbserver_command "$gdbserver :$portnum $gdbserver_server_exec"
|
||||
if { $child_args != "" } {
|
||||
append gdbserver_command " $child_args"
|
||||
# Fire off the debug agent.
|
||||
set gdbserver_command "$gdbserver"
|
||||
if { $options != "" } {
|
||||
append gdbserver_command " $options"
|
||||
}
|
||||
append gdbserver_command " :$portnum"
|
||||
if { $arguments != "" } {
|
||||
append gdbserver_command " $arguments"
|
||||
}
|
||||
|
||||
set server_spawn_id [remote_spawn target $gdbserver_command]
|
||||
|
||||
# Wait for the server to produce at least one line and an additional
|
||||
# character of output. This will wait until any TCP socket has been
|
||||
# created, so that GDB can connect.
|
||||
# Wait for the server to open its TCP socket, so that GDB can connect.
|
||||
expect {
|
||||
-i $server_spawn_id
|
||||
-notransfer
|
||||
-re ".*\n." { }
|
||||
-re "Listening on" { }
|
||||
}
|
||||
|
||||
# We can't just call close, because if gdbserver is local then that means
|
||||
@ -234,6 +242,24 @@ proc gdbserver_spawn { child_args } {
|
||||
return [list $protocol $gdbport]
|
||||
}
|
||||
|
||||
# Start a gdbserver process running SERVER_EXEC, and connect GDB
|
||||
# to it. CHILD_ARGS are passed to the inferior.
|
||||
#
|
||||
# Returns the target protocol and socket to connect to.
|
||||
|
||||
proc gdbserver_spawn { child_args } {
|
||||
set target_exec [gdbserver_download]
|
||||
|
||||
# Fire off the debug agent. This flavour of gdbserver takes as
|
||||
# arguments the port information, the name of the executable file to
|
||||
# be debugged, and any arguments.
|
||||
set arguments "$target_exec"
|
||||
if { $child_args != "" } {
|
||||
append arguments " $child_args"
|
||||
}
|
||||
return [gdbserver_start "" $arguments]
|
||||
}
|
||||
|
||||
# Start a gdbserver process running HOST_EXEC and pass CHILD_ARGS
|
||||
# to it. Return 0 on success, or non-zero on failure.
|
||||
|
||||
@ -271,3 +297,12 @@ proc gdbserver_reconnect { } {
|
||||
|
||||
return [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport]
|
||||
}
|
||||
|
||||
# Start and connect to a gdbserver in extended mode.
|
||||
proc gdbserver_start_extended { } {
|
||||
set res [gdbserver_start "--multi" ""]
|
||||
set gdbserver_protocol "extended-[lindex $res 0]"
|
||||
set gdbserver_gdbport [lindex $res 1]
|
||||
|
||||
return [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user