mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-05-31 01:45:52 +08:00
* remote.c (remote_cmdlist): New variable.
(PACKET_vFile_open, PACKET_vFile_pread, PACKET_vFile_pwrite) (PACKET_vFile_close, PACKET_vFile_unlink): New constants. (remote_buffer_add_string, remote_buffer_add_bytes) (remote_buffer_add_int, remote_hostio_parse_result) (remote_hostio_send_command, remote_hostio_open, remote_hostio_pwrite) (remote_hostio_pread, remote_hostio_close, remote_hostio_unlink) (remote_fileio_errno_to_host, remote_hostio_error, fclose_cleanup) (remote_hostio_close_cleanup, remote_file_put, remote_file_get) (remote_file_delete, remote_put_command, remote_get_command) (remote_delete_command, remote_command): New functions. (_initialize_remote): Register new packets and commands. * Makefile.in (gdb_fileio_h): New variable. (remote.o): Update. (SUBDIR_MI_OBS): Add mi-cmd-target.o. (SUBDIR_MI_SRCS): Add mi/mi-cmd-target.c. (mi-cmd-target.o): New rule. * mi/mi-cmd-target.c: New file. * mi/mi-cmds.c (mi_cmds): Add target-file-delete, target-file-get, and target-file-put. * mi/mi-cmds.h (mi_cmd_target_file_get, mi_cmd_target_file_put) (mi_cmd_target_file_delete): Declare. * remote.h (remote_file_put, remote_file_get, remote_file_delete): Declare. * NEWS: Describe new file transfer support. * gdb.texinfo (Debugging Programs with Multiple Processes): Correct formatting. (Remote Debugging): Add File Transfer section. (Remote Configuration): Document Host I/O packets. (GDB/MI): Add GDB/MI File Transfer Commands section. (Remote Protocol): Add Host I/O Packets section. (Packets): Add vFile. * Makefile.in (OBS): Add hostio.o. (hostio.o): New rule. * server.h (handle_vFile): Declare. * hostio.c: New file. * server.c (handle_v_requests): Take packet_len and new_packet_len for binary packets. Call handle_vFile. (main): Update call to handle_v_requests. * gdb.server/file-transfer.exp, gdb.server/transfer.txt, gdb.mi/mi-file-transfer.exp: New.
This commit is contained in:
@ -1,3 +1,31 @@
|
||||
2007-11-30 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* remote.c (remote_cmdlist): New variable.
|
||||
(PACKET_vFile_open, PACKET_vFile_pread, PACKET_vFile_pwrite)
|
||||
(PACKET_vFile_close, PACKET_vFile_unlink): New constants.
|
||||
(remote_buffer_add_string, remote_buffer_add_bytes)
|
||||
(remote_buffer_add_int, remote_hostio_parse_result)
|
||||
(remote_hostio_send_command, remote_hostio_open, remote_hostio_pwrite)
|
||||
(remote_hostio_pread, remote_hostio_close, remote_hostio_unlink)
|
||||
(remote_fileio_errno_to_host, remote_hostio_error, fclose_cleanup)
|
||||
(remote_hostio_close_cleanup, remote_file_put, remote_file_get)
|
||||
(remote_file_delete, remote_put_command, remote_get_command)
|
||||
(remote_delete_command, remote_command): New functions.
|
||||
(_initialize_remote): Register new packets and commands.
|
||||
* Makefile.in (gdb_fileio_h): New variable.
|
||||
(remote.o): Update.
|
||||
(SUBDIR_MI_OBS): Add mi-cmd-target.o.
|
||||
(SUBDIR_MI_SRCS): Add mi/mi-cmd-target.c.
|
||||
(mi-cmd-target.o): New rule.
|
||||
* mi/mi-cmd-target.c: New file.
|
||||
* mi/mi-cmds.c (mi_cmds): Add target-file-delete, target-file-get,
|
||||
and target-file-put.
|
||||
* mi/mi-cmds.h (mi_cmd_target_file_get, mi_cmd_target_file_put)
|
||||
(mi_cmd_target_file_delete): Declare.
|
||||
* remote.h (remote_file_put, remote_file_get, remote_file_delete):
|
||||
Declare.
|
||||
* NEWS: Describe new file transfer support.
|
||||
|
||||
2007-11-30 Vladimir Prus <vladimir@codesourcery.com>
|
||||
|
||||
* infrun.c (handle_inferior_event): Don't
|
||||
|
@ -184,7 +184,7 @@ SUBDIR_CLI_CFLAGS=
|
||||
SUBDIR_MI_OBS = \
|
||||
mi-out.o mi-console.o \
|
||||
mi-cmds.o mi-cmd-env.o mi-cmd-var.o mi-cmd-break.o mi-cmd-stack.o \
|
||||
mi-cmd-file.o mi-cmd-disas.o mi-symbol-cmds.o \
|
||||
mi-cmd-file.o mi-cmd-disas.o mi-symbol-cmds.o mi-cmd-target.o \
|
||||
mi-interp.o \
|
||||
mi-main.o mi-parse.o mi-getopt.o mi-common.o
|
||||
SUBDIR_MI_SRCS = \
|
||||
@ -192,7 +192,7 @@ SUBDIR_MI_SRCS = \
|
||||
mi/mi-cmds.c mi/mi-cmd-env.c \
|
||||
mi/mi-cmd-var.c mi/mi-cmd-break.c mi/mi-cmd-stack.c \
|
||||
mi/mi-cmd-file.c mi/mi-cmd-disas.c mi/mi-symbol-cmds.c \
|
||||
mi/mi-interp.c \
|
||||
mi/mi-cmd-target.c mi/mi-interp.c \
|
||||
mi/mi-main.c mi/mi-parse.c mi/mi-getopt.c mi/mi-common.c
|
||||
SUBDIR_MI_DEPS =
|
||||
SUBDIR_MI_LDFLAGS=
|
||||
@ -675,6 +675,7 @@ mep_desc_h = $(OPCODES_SRC)/mep-desc.h
|
||||
mep_opc_h = $(OPCODES_SRC)/mep-opc.h
|
||||
sh_opc_h = $(OPCODES_SRC)/sh-opc.h
|
||||
gdb_callback_h = $(INCLUDE_DIR)/gdb/callback.h
|
||||
gdb_fileio_h = $(INCLUDE_DIR)/gdb/fileio.h
|
||||
gdb_sim_arm_h = $(INCLUDE_DIR)/gdb/sim-arm.h
|
||||
gdb_sim_frv_h = $(INCLUDE_DIR)/gdb/sim-frv.h
|
||||
gdb_sim_m32c_h = $(INCLUDE_DIR)/gdb/sim-m32c.h
|
||||
@ -2602,7 +2603,8 @@ remote.o: remote.c $(defs_h) $(gdb_string_h) $(inferior_h) $(bfd_h) \
|
||||
$(gdb_stabs_h) $(gdbthread_h) $(remote_h) $(regcache_h) $(value_h) \
|
||||
$(gdb_assert_h) $(event_loop_h) $(event_top_h) $(inf_loop_h) \
|
||||
$(serial_h) $(gdbcore_h) $(remote_fileio_h) $(solib_h) $(observer_h) \
|
||||
$(cli_decode_h) $(cli_setshow_h) $(memory_map_h) $(target_descriptions_h)
|
||||
$(cli_decode_h) $(cli_setshow_h) $(memory_map_h) \
|
||||
$(target_descriptions_h) $(gdb_fileio_h)
|
||||
remote-fileio.o: remote-fileio.c $(defs_h) $(gdb_string_h) $(gdbcmd_h) \
|
||||
$(remote_h) $(gdb_fileio_h) $(gdb_wait_h) $(gdb_stat_h) \
|
||||
$(exceptions_h) $(remote_fileio_h)
|
||||
@ -3186,6 +3188,9 @@ mi-cmd-stack.o: $(srcdir)/mi/mi-cmd-stack.c $(defs_h) $(target_h) $(frame_h) \
|
||||
$(value_h) $(mi_cmds_h) $(ui_out_h) $(symtab_h) $(block_h) \
|
||||
$(stack_h) $(dictionary_h) $(gdb_string_h)
|
||||
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-cmd-stack.c
|
||||
mi-cmd-target.o: $(srcdir)/mi/mi-cmd-target.c $(defs_h) $(mi_cmds_h) \
|
||||
$(mi_getopt_h) $(remote_h)
|
||||
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-cmd-target.c
|
||||
mi-cmd-var.o: $(srcdir)/mi/mi-cmd-var.c $(defs_h) $(mi_cmds_h) $(ui_out_h) \
|
||||
$(mi_out_h) $(varobj_h) $(value_h) $(gdb_string_h)
|
||||
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/mi/mi-cmd-var.c
|
||||
|
25
gdb/NEWS
25
gdb/NEWS
@ -28,6 +28,9 @@ registers on PowerPC targets.
|
||||
* The GDB remote stub, gdbserver, now supports thread debugging on GNU/Linux
|
||||
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).
|
||||
|
||||
* 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".
|
||||
@ -37,6 +40,28 @@ targets even when the libthread_db library is not available.
|
||||
building a single GDB executable that supports multiple remote
|
||||
target architectures.
|
||||
|
||||
* New commands
|
||||
|
||||
remote put
|
||||
remote get
|
||||
remote delete
|
||||
Transfer files to and from a remote target, and delete remote files.
|
||||
|
||||
* New MI commands
|
||||
|
||||
-target-file-put
|
||||
-target-file-get
|
||||
-target-file-delete
|
||||
Transfer files to and from a remote target, and delete remote files.
|
||||
|
||||
* New remote packets
|
||||
|
||||
vFile:open:
|
||||
vFile:close:
|
||||
vFile:pread:
|
||||
vFile:pwrite:
|
||||
vFile:unlink:
|
||||
Open, close, read, write, and delete files on the remote system.
|
||||
|
||||
*** Changes in GDB 6.7
|
||||
|
||||
|
@ -1,3 +1,13 @@
|
||||
2007-11-30 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.texinfo (Debugging Programs with Multiple Processes): Correct
|
||||
formatting.
|
||||
(Remote Debugging): Add File Transfer section.
|
||||
(Remote Configuration): Document Host I/O packets.
|
||||
(GDB/MI): Add GDB/MI File Transfer Commands section.
|
||||
(Remote Protocol): Add Host I/O Packets section.
|
||||
(Packets): Add vFile.
|
||||
|
||||
2007-11-17 Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
* gdb.texinfo (Set Breaks, Disabling): Clarify behavior of
|
||||
|
@ -2480,7 +2480,7 @@ the child process just like any other process which you attached to.
|
||||
On some systems, @value{GDBN} provides support for debugging programs that
|
||||
create additional processes using the @code{fork} or @code{vfork} functions.
|
||||
Currently, the only platforms with this feature are HP-UX (11.x and later
|
||||
only?) and GNU/Linux (kernel version 2.5.60 and later).
|
||||
only?) and @sc{gnu}/Linux (kernel version 2.5.60 and later).
|
||||
|
||||
By default, when a program forks, @value{GDBN} will continue to debug
|
||||
the parent process and the child process will run unimpeded.
|
||||
@ -12670,6 +12670,7 @@ configuration of @value{GDBN}; use @code{help target} to list them.
|
||||
|
||||
@menu
|
||||
* Connecting:: Connecting to a remote target
|
||||
* File Transfer:: Sending files to a remote system
|
||||
* Server:: Using the gdbserver program
|
||||
* Remote Configuration:: Remote configuration
|
||||
* Remote Stub:: Implementing a remote stub
|
||||
@ -12817,6 +12818,38 @@ can add new commands that only the external monitor will understand
|
||||
and implement.
|
||||
@end table
|
||||
|
||||
@node File Transfer
|
||||
@section Sending files to a remote system
|
||||
@cindex remote target, file transfer
|
||||
@cindex file transfer
|
||||
@cindex sending files to remote systems
|
||||
|
||||
Some remote targets offer the ability to transfer files over the same
|
||||
connection used to communicate with @value{GDBN}. This is convenient
|
||||
for targets accessible through other means, e.g.@: @sc{gnu}/Linux systems
|
||||
running @code{gdbserver} over a network interface. For other targets,
|
||||
e.g.@: embedded devices with only a single serial port, this may be
|
||||
the only way to upload or download files.
|
||||
|
||||
Not all remote targets support these commands.
|
||||
|
||||
@table @code
|
||||
@kindex remote put
|
||||
@item remote put @var{hostfile} @var{targetfile}
|
||||
Copy file @var{hostfile} from the host system (the machine running
|
||||
@value{GDBN}) to @var{targetfile} on the target system.
|
||||
|
||||
@kindex remote get
|
||||
@item remote get @var{targetfile} @var{hostfile}
|
||||
Copy file @var{targetfile} from the target system to @var{hostfile}
|
||||
on the host system.
|
||||
|
||||
@kindex remote delete
|
||||
@item remote delete @var{targetfile}
|
||||
Delete @var{targetfile} from the target system.
|
||||
|
||||
@end table
|
||||
|
||||
@node Server
|
||||
@section Using the @code{gdbserver} Program
|
||||
|
||||
@ -13153,6 +13186,25 @@ are:
|
||||
@tab @code{QPassSignals}
|
||||
@tab @code{handle @var{signal}}
|
||||
|
||||
@item @code{hostio-close-packet}
|
||||
@tab @code{vFile:close}
|
||||
@tab @code{remote get}, @code{remote put}
|
||||
|
||||
@item @code{hostio-open-packet}
|
||||
@tab @code{vFile:open}
|
||||
@tab @code{remote get}, @code{remote put}
|
||||
|
||||
@item @code{hostio-pread-packet}
|
||||
@tab @code{vFile:pread}
|
||||
@tab @code{remote get}, @code{remote put}
|
||||
|
||||
@item @code{hostio-pwrite-packet}
|
||||
@tab @code{vFile:pwrite}
|
||||
@tab @code{remote get}, @code{remote put}
|
||||
|
||||
@item @code{hostio-unlink-packet}
|
||||
@tab @code{vFile:unlink}
|
||||
@tab @code{remote delete}
|
||||
@end multitable
|
||||
|
||||
@node Remote Stub
|
||||
@ -17349,6 +17401,7 @@ may repeat one or more times.
|
||||
* GDB/MI Signal Handling Commands::
|
||||
@end ignore
|
||||
* GDB/MI Target Manipulation::
|
||||
* GDB/MI File Transfer Commands::
|
||||
* GDB/MI Miscellaneous Commands::
|
||||
@end menu
|
||||
|
||||
@ -21295,6 +21348,88 @@ The corresponding @value{GDBN} command is @samp{target}.
|
||||
(gdb)
|
||||
@end smallexample
|
||||
|
||||
@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@node GDB/MI File Transfer Commands
|
||||
@section @sc{gdb/mi} File Transfer Commands
|
||||
|
||||
|
||||
@subheading The @code{-target-file-put} Command
|
||||
@findex -target-file-put
|
||||
|
||||
@subsubheading Synopsis
|
||||
|
||||
@smallexample
|
||||
-target-file-put @var{hostfile} @var{targetfile}
|
||||
@end smallexample
|
||||
|
||||
Copy file @var{hostfile} from the host system (the machine running
|
||||
@value{GDBN}) to @var{targetfile} on the target system.
|
||||
|
||||
@subsubheading @value{GDBN} Command
|
||||
|
||||
The corresponding @value{GDBN} command is @samp{remote put}.
|
||||
|
||||
@subsubheading Example
|
||||
|
||||
@smallexample
|
||||
(gdb)
|
||||
-target-file-put localfile remotefile
|
||||
^done
|
||||
(gdb)
|
||||
@end smallexample
|
||||
|
||||
|
||||
@subheading The @code{-target-file-put} Command
|
||||
@findex -target-file-get
|
||||
|
||||
@subsubheading Synopsis
|
||||
|
||||
@smallexample
|
||||
-target-file-get @var{targetfile} @var{hostfile}
|
||||
@end smallexample
|
||||
|
||||
Copy file @var{targetfile} from the target system to @var{hostfile}
|
||||
on the host system.
|
||||
|
||||
@subsubheading @value{GDBN} Command
|
||||
|
||||
The corresponding @value{GDBN} command is @samp{remote get}.
|
||||
|
||||
@subsubheading Example
|
||||
|
||||
@smallexample
|
||||
(gdb)
|
||||
-target-file-get remotefile localfile
|
||||
^done
|
||||
(gdb)
|
||||
@end smallexample
|
||||
|
||||
|
||||
@subheading The @code{-target-file-delete} Command
|
||||
@findex -target-file-delete
|
||||
|
||||
@subsubheading Synopsis
|
||||
|
||||
@smallexample
|
||||
-target-file-delete @var{targetfile}
|
||||
@end smallexample
|
||||
|
||||
Delete @var{targetfile} from the target system.
|
||||
|
||||
@subsubheading @value{GDBN} Command
|
||||
|
||||
The corresponding @value{GDBN} command is @samp{remote delete}.
|
||||
|
||||
@subsubheading Example
|
||||
|
||||
@smallexample
|
||||
(gdb)
|
||||
-target-file-delete remotefile
|
||||
^done
|
||||
(gdb)
|
||||
@end smallexample
|
||||
|
||||
|
||||
@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@node GDB/MI Miscellaneous Commands
|
||||
@section Miscellaneous @sc{gdb/mi} Commands
|
||||
@ -22920,6 +23055,7 @@ Show the current setting of the target wait timeout.
|
||||
* General Query Packets::
|
||||
* Register Packet Format::
|
||||
* Tracepoint Packets::
|
||||
* Host I/O Packets::
|
||||
* Interrupts::
|
||||
* Examples::
|
||||
* File-I/O Remote Protocol Extension::
|
||||
@ -23423,6 +23559,11 @@ command in the @samp{vCont} packet.
|
||||
The @samp{vCont} packet is not supported.
|
||||
@end table
|
||||
|
||||
@item vFile:@var{operation}:@var{parameter}@dots{}
|
||||
@cindex @samp{vFile} packet
|
||||
Perform a file operation on the target system. For details,
|
||||
see @ref{Host I/O Packets}.
|
||||
|
||||
@item vFlashErase:@var{addr},@var{length}
|
||||
@cindex @samp{vFlashErase} packet
|
||||
Direct the stub to erase @var{length} bytes of flash starting at
|
||||
@ -24572,6 +24713,104 @@ There is a trace experiment running.
|
||||
@end table
|
||||
|
||||
|
||||
@node Host I/O Packets
|
||||
@section Host I/O Packets
|
||||
@cindex Host I/O, remote protocol
|
||||
@cindex file transfer, remote protocol
|
||||
|
||||
The @dfn{Host I/O} packets allow @value{GDBN} to perform I/O
|
||||
operations on the far side of a remote link. For example, Host I/O is
|
||||
used to upload and download files to a remote target with its own
|
||||
filesystem. Host I/O uses the same constant values and data structure
|
||||
layout as the target-initiated File-I/O protocol. However, the
|
||||
Host I/O packets are structured differently. The target-initiated
|
||||
protocol relies on target memory to store parameters and buffers.
|
||||
Host I/O requests are initiated by @value{GDBN}, and the
|
||||
target's memory is not involved. @xref{File-I/O Remote Protocol
|
||||
Extension}, for more details on the target-initiated protocol.
|
||||
|
||||
The Host I/O request packets all encode a single operation along with
|
||||
its arguments. They have this format:
|
||||
|
||||
@table @samp
|
||||
|
||||
@item vFile:@var{operation}: @var{parameter}@dots{}
|
||||
@var{operation} is the name of the particular request; the target
|
||||
should compare the entire packet name up to the second colon when checking
|
||||
for a supported operation. The format of @var{parameter} depends on
|
||||
the operation. Numbers are always passed in hexadecimal. Negative
|
||||
numbers have an explicit minus sign (i.e.@: two's complement is not
|
||||
used). Strings (e.g.@: filenames) are encoded as a series of
|
||||
hexadecimal bytes. The last argument to a system call may be a
|
||||
buffer of escaped binary data (@pxref{Binary Data}).
|
||||
|
||||
@end table
|
||||
|
||||
The valid responses to Host I/O packets are:
|
||||
|
||||
@table @samp
|
||||
|
||||
@item F @var{result} [, @var{errno}] [; @var{attachment}]
|
||||
@var{result} is the integer value returned by this operation, usually
|
||||
non-negative for success and -1 for errors. If an error has occured,
|
||||
@var{errno} will be included in the result. @var{errno} will have a
|
||||
value defined by the File-I/O protocol (@pxref{Errno Values}). For
|
||||
operations which return data, @var{attachment} supplies the data as a
|
||||
binary buffer. Binary buffers in response packets are escaped in the
|
||||
normal way (@pxref{Binary Data}). See the individual packet
|
||||
documentation for the interpretation of @var{result} and
|
||||
@var{attachment}.
|
||||
|
||||
@item
|
||||
An empty response indicates that this operation is not recognized.
|
||||
|
||||
@end table
|
||||
|
||||
These are the supported Host I/O operations:
|
||||
|
||||
@table @samp
|
||||
@item vFile:open: @var{pathname}, @var{flags}, @var{mode}
|
||||
Open a file at @var{pathname} and return a file descriptor for it, or
|
||||
return -1 if an error occurs. @var{pathname} is a string,
|
||||
@var{flags} is an integer indicating a mask of open flags
|
||||
(@pxref{Open Flags}), and @var{mode} is an integer indicating a mask
|
||||
of mode bits to use if the file is created (@pxref{mode_t Values}).
|
||||
@xref{open} for details of the open flags and mode values.
|
||||
|
||||
@item vFile:close: @var{fd}
|
||||
Close the open file corresponding to @var{fd} and return 0, or
|
||||
-1 if an error occurs.
|
||||
|
||||
@item vFile:pread: @var{fd}, @var{count}, @var{offset}
|
||||
Read data from the open file corresponding to @var{fd}. Up to
|
||||
@var{count} bytes will be read from the file, starting at @var{offset}
|
||||
relative to the start of the file. The target may read fewer bytes;
|
||||
common reasons include packet size limits and an end-of-file
|
||||
condition. The number of bytes read is returned. Zero should only be
|
||||
returned for a successful read at the end of the file, or if
|
||||
@var{count} was zero.
|
||||
|
||||
The data read should be returned as a binary attachment on success.
|
||||
If zero bytes were read, the response should include an empty binary
|
||||
attachment (i.e.@: a trailing semicolon). The return value is the
|
||||
number of target bytes read; the binary attachment may be longer if
|
||||
some characters were escaped.
|
||||
|
||||
@item vFile:pwrite: @var{fd}, @var{offset}, @var{data}
|
||||
Write @var{data} (a binary buffer) to the open file corresponding
|
||||
to @var{fd}. Start the write at @var{offset} from the start of the
|
||||
file. Unlike many @code{write} system calls, there is no
|
||||
separate @var{count} argument; the length of @var{data} in the
|
||||
packet is used. @samp{vFile:write} returns the number of bytes written,
|
||||
which may be shorter than the length of @var{data}, or -1 if an
|
||||
error occurred.
|
||||
|
||||
@item vFile:unlink: @var{pathname}
|
||||
Delete the file at @var{pathname} on the target. Return 0,
|
||||
or -1 if an error occurs. @var{pathname} is a string.
|
||||
|
||||
@end table
|
||||
|
||||
@node Interrupts
|
||||
@section Interrupts
|
||||
@cindex interrupts (remote protocol)
|
||||
|
@ -1,3 +1,13 @@
|
||||
2007-11-30 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* Makefile.in (OBS): Add hostio.o.
|
||||
(hostio.o): New rule.
|
||||
* server.h (handle_vFile): Declare.
|
||||
* hostio.c: New file.
|
||||
* server.c (handle_v_requests): Take packet_len and new_packet_len
|
||||
for binary packets. Call handle_vFile.
|
||||
(main): Update call to handle_v_requests.
|
||||
|
||||
2007-11-05 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* linux-low.c: Include <sched.h>.
|
||||
|
@ -139,7 +139,7 @@ TAGFILES = $(SOURCES) ${HFILES} ${ALLPARAM} ${POSSLIBS}
|
||||
|
||||
OBS = inferiors.o regcache.o remote-utils.o server.o signals.o target.o \
|
||||
utils.o version.o \
|
||||
mem-break.o \
|
||||
mem-break.o hostio.o \
|
||||
$(XML_BUILTIN) \
|
||||
$(DEPFILES)
|
||||
GDBSERVER_LIBS = @GDBSERVER_LIBS@
|
||||
@ -277,6 +277,7 @@ regcache_h = $(srcdir)/regcache.h
|
||||
server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \
|
||||
$(srcdir)/mem-break.h
|
||||
|
||||
hostio.o: hostio.c $(server_h)
|
||||
inferiors.o: inferiors.c $(server_h)
|
||||
mem-break.o: mem-break.c $(server_h)
|
||||
proc-service.o: proc-service.c $(server_h) $(gdb_proc_service_h)
|
||||
|
517
gdb/gdbserver/hostio.c
Normal file
517
gdb/gdbserver/hostio.c
Normal file
@ -0,0 +1,517 @@
|
||||
/* Host file transfer support for gdbserver.
|
||||
Copyright (C) 2006
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
Contributed by CodeSourcery.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "server.h"
|
||||
#include "gdb/fileio.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern int remote_debug;
|
||||
|
||||
struct fd_list
|
||||
{
|
||||
int fd;
|
||||
struct fd_list *next;
|
||||
};
|
||||
|
||||
static struct fd_list *open_fds;
|
||||
|
||||
static int
|
||||
safe_fromhex (char a, int *nibble)
|
||||
{
|
||||
if (a >= '0' && a <= '9')
|
||||
*nibble = a - '0';
|
||||
else if (a >= 'a' && a <= 'f')
|
||||
*nibble = a - 'a' + 10;
|
||||
else if (a >= 'A' && a <= 'F')
|
||||
*nibble = a - 'A' + 10;
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
require_filename (char **pp, char *filename)
|
||||
{
|
||||
int count;
|
||||
char *p;
|
||||
|
||||
p = *pp;
|
||||
count = 0;
|
||||
|
||||
while (*p && *p != ',')
|
||||
{
|
||||
int nib1, nib2;
|
||||
|
||||
/* Don't allow overflow. */
|
||||
if (count >= PATH_MAX - 1)
|
||||
return -1;
|
||||
|
||||
if (safe_fromhex (p[0], &nib1)
|
||||
|| safe_fromhex (p[1], &nib2))
|
||||
return -1;
|
||||
|
||||
filename[count++] = nib1 * 16 + nib2;
|
||||
p += 2;
|
||||
}
|
||||
|
||||
filename[count] = '\0';
|
||||
*pp = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
require_int (char **pp, int *value)
|
||||
{
|
||||
char *p;
|
||||
int count;
|
||||
|
||||
p = *pp;
|
||||
*value = 0;
|
||||
count = 0;
|
||||
|
||||
while (*p && *p != ',')
|
||||
{
|
||||
int nib;
|
||||
|
||||
/* Don't allow overflow. */
|
||||
if (count >= 7)
|
||||
return -1;
|
||||
|
||||
if (safe_fromhex (p[0], &nib))
|
||||
return -1;
|
||||
*value = *value * 16 + nib;
|
||||
p++;
|
||||
count++;
|
||||
}
|
||||
|
||||
*pp = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
require_data (char *p, int p_len, char **data, int *data_len)
|
||||
{
|
||||
int input_index, output_index, escaped;
|
||||
|
||||
*data = malloc (p_len);
|
||||
|
||||
output_index = 0;
|
||||
escaped = 0;
|
||||
for (input_index = 0; input_index < p_len; input_index++)
|
||||
{
|
||||
char b = p[input_index];
|
||||
|
||||
if (escaped)
|
||||
{
|
||||
(*data)[output_index++] = b ^ 0x20;
|
||||
escaped = 0;
|
||||
}
|
||||
else if (b == '}')
|
||||
escaped = 1;
|
||||
else
|
||||
(*data)[output_index++] = b;
|
||||
}
|
||||
|
||||
if (escaped)
|
||||
return -1;
|
||||
|
||||
*data_len = output_index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
require_comma (char **pp)
|
||||
{
|
||||
if (**pp == ',')
|
||||
{
|
||||
(*pp)++;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
require_end (char *p)
|
||||
{
|
||||
if (*p == '\0')
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
require_valid_fd (int fd)
|
||||
{
|
||||
struct fd_list *fd_ptr;
|
||||
|
||||
for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
|
||||
if (fd_ptr->fd == fd)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
errno_to_fileio_errno (int error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case EPERM:
|
||||
return FILEIO_EPERM;
|
||||
case ENOENT:
|
||||
return FILEIO_ENOENT;
|
||||
case EINTR:
|
||||
return FILEIO_EINTR;
|
||||
case EIO:
|
||||
return FILEIO_EIO;
|
||||
case EBADF:
|
||||
return FILEIO_EBADF;
|
||||
case EACCES:
|
||||
return FILEIO_EACCES;
|
||||
case EFAULT:
|
||||
return FILEIO_EFAULT;
|
||||
case EBUSY:
|
||||
return FILEIO_EBUSY;
|
||||
case EEXIST:
|
||||
return FILEIO_EEXIST;
|
||||
case ENODEV:
|
||||
return FILEIO_ENODEV;
|
||||
case ENOTDIR:
|
||||
return FILEIO_ENOTDIR;
|
||||
case EISDIR:
|
||||
return FILEIO_EISDIR;
|
||||
case EINVAL:
|
||||
return FILEIO_EINVAL;
|
||||
case ENFILE:
|
||||
return FILEIO_ENFILE;
|
||||
case EMFILE:
|
||||
return FILEIO_EMFILE;
|
||||
case EFBIG:
|
||||
return FILEIO_EFBIG;
|
||||
case ENOSPC:
|
||||
return FILEIO_ENOSPC;
|
||||
case ESPIPE:
|
||||
return FILEIO_ESPIPE;
|
||||
case EROFS:
|
||||
return FILEIO_EROFS;
|
||||
case ENOSYS:
|
||||
return FILEIO_ENOSYS;
|
||||
case ENAMETOOLONG:
|
||||
return FILEIO_ENAMETOOLONG;
|
||||
}
|
||||
return FILEIO_EUNKNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
hostio_error (char *own_buf, int error)
|
||||
{
|
||||
int fileio_error = errno_to_fileio_errno (error);
|
||||
|
||||
sprintf (own_buf, "F-1,%x", fileio_error);
|
||||
}
|
||||
|
||||
static void
|
||||
hostio_packet_error (char *own_buf)
|
||||
{
|
||||
hostio_error (own_buf, EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
hostio_reply (char *own_buf, int result)
|
||||
{
|
||||
sprintf (own_buf, "F%x", result);
|
||||
}
|
||||
|
||||
static int
|
||||
hostio_reply_with_data (char *own_buf, char *buffer, int len,
|
||||
int *new_packet_len)
|
||||
{
|
||||
int input_index, output_index, out_maxlen;
|
||||
|
||||
sprintf (own_buf, "F%x;", len);
|
||||
output_index = strlen (own_buf);
|
||||
|
||||
out_maxlen = PBUFSIZ;
|
||||
|
||||
for (input_index = 0; input_index < len; input_index++)
|
||||
{
|
||||
char b = buffer[input_index];
|
||||
|
||||
if (b == '$' || b == '#' || b == '}' || b == '*')
|
||||
{
|
||||
/* These must be escaped. */
|
||||
if (output_index + 2 > out_maxlen)
|
||||
break;
|
||||
own_buf[output_index++] = '}';
|
||||
own_buf[output_index++] = b ^ 0x20;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (output_index + 1 > out_maxlen)
|
||||
break;
|
||||
own_buf[output_index++] = b;
|
||||
}
|
||||
}
|
||||
|
||||
*new_packet_len = output_index;
|
||||
return input_index;
|
||||
}
|
||||
|
||||
static int
|
||||
fileio_open_flags_to_host (int fileio_open_flags, int *open_flags_p)
|
||||
{
|
||||
int open_flags = 0;
|
||||
|
||||
if (fileio_open_flags & ~FILEIO_O_SUPPORTED)
|
||||
return -1;
|
||||
|
||||
if (fileio_open_flags & FILEIO_O_CREAT)
|
||||
open_flags |= O_CREAT;
|
||||
if (fileio_open_flags & FILEIO_O_EXCL)
|
||||
open_flags |= O_EXCL;
|
||||
if (fileio_open_flags & FILEIO_O_TRUNC)
|
||||
open_flags |= O_TRUNC;
|
||||
if (fileio_open_flags & FILEIO_O_APPEND)
|
||||
open_flags |= O_APPEND;
|
||||
if (fileio_open_flags & FILEIO_O_RDONLY)
|
||||
open_flags |= O_RDONLY;
|
||||
if (fileio_open_flags & FILEIO_O_WRONLY)
|
||||
open_flags |= O_WRONLY;
|
||||
if (fileio_open_flags & FILEIO_O_RDWR)
|
||||
open_flags |= O_RDWR;
|
||||
/* On systems supporting binary and text mode, always open files in
|
||||
binary mode. */
|
||||
#ifdef O_BINARY
|
||||
open_flags |= O_BINARY;
|
||||
#endif
|
||||
|
||||
*open_flags_p = open_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_open (char *own_buf)
|
||||
{
|
||||
char filename[PATH_MAX];
|
||||
char *p;
|
||||
int fileio_flags, mode, flags, fd;
|
||||
struct fd_list *new_fd;
|
||||
|
||||
p = own_buf + strlen ("vFile:open:");
|
||||
|
||||
if (require_filename (&p, filename)
|
||||
|| require_comma (&p)
|
||||
|| require_int (&p, &fileio_flags)
|
||||
|| require_comma (&p)
|
||||
|| require_int (&p, &mode)
|
||||
|| require_end (p)
|
||||
|| fileio_open_flags_to_host (fileio_flags, &flags))
|
||||
{
|
||||
hostio_packet_error (own_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We do not need to convert MODE, since the fileio protocol
|
||||
uses the standard values. */
|
||||
fd = open (filename, flags, mode);
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
hostio_error (own_buf, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Record the new file descriptor. */
|
||||
new_fd = malloc (sizeof (struct fd_list));
|
||||
new_fd->fd = fd;
|
||||
new_fd->next = open_fds;
|
||||
open_fds = new_fd;
|
||||
|
||||
hostio_reply (own_buf, fd);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_pread (char *own_buf, int *new_packet_len)
|
||||
{
|
||||
int fd, ret, len, offset, bytes_sent;
|
||||
char *p, *data;
|
||||
|
||||
p = own_buf + strlen ("vFile:pread:");
|
||||
|
||||
if (require_int (&p, &fd)
|
||||
|| require_comma (&p)
|
||||
|| require_valid_fd (fd)
|
||||
|| require_int (&p, &len)
|
||||
|| require_comma (&p)
|
||||
|| require_int (&p, &offset)
|
||||
|| require_end (p))
|
||||
{
|
||||
hostio_packet_error (own_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
data = malloc (len);
|
||||
ret = pread (fd, data, len, offset);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
hostio_error (own_buf, errno);
|
||||
free (data);
|
||||
return;
|
||||
}
|
||||
|
||||
bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
|
||||
|
||||
/* If we were using read, and the data did not all fit in the reply,
|
||||
we would have to back up using lseek here. With pread it does
|
||||
not matter. But we still have a problem; the return value in the
|
||||
packet might be wrong, so we must fix it. This time it will
|
||||
definitely fit. */
|
||||
if (bytes_sent < ret)
|
||||
bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
|
||||
new_packet_len);
|
||||
|
||||
free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_pwrite (char *own_buf, int packet_len)
|
||||
{
|
||||
int fd, ret, len, offset;
|
||||
char *p, *data;
|
||||
|
||||
p = own_buf + strlen ("vFile:pwrite:");
|
||||
|
||||
if (require_int (&p, &fd)
|
||||
|| require_comma (&p)
|
||||
|| require_valid_fd (fd)
|
||||
|| require_int (&p, &offset)
|
||||
|| require_comma (&p)
|
||||
|| require_data (p, packet_len - (p - own_buf), &data, &len))
|
||||
{
|
||||
hostio_packet_error (own_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = pwrite (fd, data, len, offset);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
hostio_error (own_buf, errno);
|
||||
free (data);
|
||||
return;
|
||||
}
|
||||
|
||||
hostio_reply (own_buf, ret);
|
||||
free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_close (char *own_buf)
|
||||
{
|
||||
int fd, ret;
|
||||
char *p;
|
||||
struct fd_list **open_fd_p, *old_fd;
|
||||
|
||||
p = own_buf + strlen ("vFile:close:");
|
||||
|
||||
if (require_int (&p, &fd)
|
||||
|| require_valid_fd (fd)
|
||||
|| require_end (p))
|
||||
{
|
||||
hostio_packet_error (own_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = close (fd);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
hostio_error (own_buf, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
open_fd_p = &open_fds;
|
||||
while (*open_fd_p && (*open_fd_p)->fd != fd)
|
||||
open_fd_p = &(*open_fd_p)->next;
|
||||
|
||||
old_fd = *open_fd_p;
|
||||
*open_fd_p = (*open_fd_p)->next;
|
||||
free (old_fd);
|
||||
|
||||
hostio_reply (own_buf, ret);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_unlink (char *own_buf)
|
||||
{
|
||||
char filename[PATH_MAX];
|
||||
char *p;
|
||||
int ret;
|
||||
|
||||
p = own_buf + strlen ("vFile:unlink:");
|
||||
|
||||
if (require_filename (&p, filename)
|
||||
|| require_end (p))
|
||||
{
|
||||
hostio_packet_error (own_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = unlink (filename);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
hostio_error (own_buf, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
hostio_reply (own_buf, ret);
|
||||
}
|
||||
|
||||
/* Handle all the 'F' file transfer packets. */
|
||||
|
||||
int
|
||||
handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
|
||||
{
|
||||
if (strncmp (own_buf, "vFile:open:", 11) == 0)
|
||||
handle_open (own_buf);
|
||||
else if (strncmp (own_buf, "vFile:pread:", 11) == 0)
|
||||
handle_pread (own_buf, new_packet_len);
|
||||
else if (strncmp (own_buf, "vFile:pwrite:", 12) == 0)
|
||||
handle_pwrite (own_buf, packet_len);
|
||||
else if (strncmp (own_buf, "vFile:close:", 12) == 0)
|
||||
handle_close (own_buf);
|
||||
else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
|
||||
handle_unlink (own_buf);
|
||||
else
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
@ -772,7 +772,8 @@ err:
|
||||
|
||||
/* Handle all of the extended 'v' packets. */
|
||||
void
|
||||
handle_v_requests (char *own_buf, char *status, int *signal)
|
||||
handle_v_requests (char *own_buf, char *status, int *signal,
|
||||
int packet_len, int *new_packet_len)
|
||||
{
|
||||
if (strncmp (own_buf, "vCont;", 6) == 0)
|
||||
{
|
||||
@ -786,6 +787,10 @@ handle_v_requests (char *own_buf, char *status, int *signal)
|
||||
return;
|
||||
}
|
||||
|
||||
if (strncmp (own_buf, "vFile:", 6) == 0
|
||||
&& handle_vFile (own_buf, packet_len, new_packet_len))
|
||||
return;
|
||||
|
||||
/* Otherwise we didn't know what packet it was. Say we didn't
|
||||
understand it. */
|
||||
own_buf[0] = 0;
|
||||
@ -1218,8 +1223,10 @@ main (int argc, char *argv[])
|
||||
}
|
||||
case 'v':
|
||||
/* Extended (long) request. */
|
||||
handle_v_requests (own_buf, &status, &signal);
|
||||
handle_v_requests (own_buf, &status, &signal,
|
||||
packet_len, &new_packet_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* It is a request we don't understand. Respond with an
|
||||
empty packet so that gdb knows that we don't support this
|
||||
|
@ -156,6 +156,9 @@ extern int pass_signals[];
|
||||
|
||||
extern jmp_buf toplevel;
|
||||
|
||||
/* Functions from hostio.c. */
|
||||
extern int handle_vFile (char *, int, int *);
|
||||
|
||||
/* From remote-utils.c */
|
||||
|
||||
extern int remote_debug;
|
||||
|
100
gdb/mi/mi-cmd-target.c
Normal file
100
gdb/mi/mi-cmd-target.c
Normal file
@ -0,0 +1,100 @@
|
||||
/* MI Command Set - target commands.
|
||||
Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
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/>. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "mi-cmds.h"
|
||||
#include "mi-getopt.h"
|
||||
#include "remote.h"
|
||||
|
||||
/* Get a file from the target. */
|
||||
|
||||
enum mi_cmd_result
|
||||
mi_cmd_target_file_get (char *command, char **argv, int argc)
|
||||
{
|
||||
int optind = 0;
|
||||
char *optarg;
|
||||
const char *remote_file, *local_file;
|
||||
static struct mi_opt opts[] =
|
||||
{
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
static const char *prefix = "mi_cmd_target_file_get";
|
||||
|
||||
if (mi_getopt (prefix, argc, argv, opts, &optind, &optarg) != -1
|
||||
|| optind != argc - 2)
|
||||
error (_("mi_cmd_target_file_get: Usage: REMOTE_FILE LOCAL_FILE"));
|
||||
|
||||
remote_file = argv[optind];
|
||||
local_file = argv[optind + 1];
|
||||
|
||||
remote_file_get (remote_file, local_file, 0);
|
||||
|
||||
return MI_CMD_DONE;
|
||||
}
|
||||
|
||||
/* Send a file to the target. */
|
||||
|
||||
enum mi_cmd_result
|
||||
mi_cmd_target_file_put (char *command, char **argv, int argc)
|
||||
{
|
||||
int optind = 0;
|
||||
char *optarg;
|
||||
const char *remote_file, *local_file;
|
||||
static struct mi_opt opts[] =
|
||||
{
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
static const char *prefix = "mi_cmd_target_file_put";
|
||||
|
||||
if (mi_getopt (prefix, argc, argv, opts, &optind, &optarg) != -1
|
||||
|| optind != argc - 2)
|
||||
error (_("mi_cmd_target_file_put: Usage: LOCAL_FILE REMOTE_FILE"));
|
||||
|
||||
local_file = argv[optind];
|
||||
remote_file = argv[optind + 1];
|
||||
|
||||
remote_file_put (local_file, remote_file, 0);
|
||||
|
||||
return MI_CMD_DONE;
|
||||
}
|
||||
|
||||
/* Delete a file on the target. */
|
||||
|
||||
enum mi_cmd_result
|
||||
mi_cmd_target_file_delete (char *command, char **argv, int argc)
|
||||
{
|
||||
int optind = 0;
|
||||
char *optarg;
|
||||
const char *remote_file, *local_file;
|
||||
static struct mi_opt opts[] =
|
||||
{
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
static const char *prefix = "mi_cmd_target_file_delete";
|
||||
|
||||
if (mi_getopt (prefix, argc, argv, opts, &optind, &optarg) != -1
|
||||
|| optind != argc - 1)
|
||||
error (_("mi_cmd_target_file_delete: Usage: REMOTE_FILE"));
|
||||
|
||||
remote_file = argv[optind];
|
||||
|
||||
remote_file_delete (remote_file, 0);
|
||||
|
||||
return MI_CMD_DONE;
|
||||
}
|
||||
|
@ -123,6 +123,9 @@ struct mi_cmd mi_cmds[] =
|
||||
{ "target-disconnect", { "disconnect", 0 }, 0 },
|
||||
{ "target-download", { NULL, 0 }, mi_cmd_target_download},
|
||||
{ "target-exec-status", { NULL, 0 }, NULL, NULL },
|
||||
{ "target-file-delete", { NULL, 0 }, NULL, mi_cmd_target_file_delete },
|
||||
{ "target-file-get", { NULL, 0 }, NULL, mi_cmd_target_file_get },
|
||||
{ "target-file-put", { NULL, 0 }, NULL, mi_cmd_target_file_put },
|
||||
{ "target-list-available-targets", { NULL, 0 }, NULL, NULL },
|
||||
{ "target-list-current-targets", { NULL, 0 }, NULL, NULL },
|
||||
{ "target-list-parameters", { NULL, 0 }, NULL, NULL },
|
||||
|
@ -100,6 +100,9 @@ extern mi_cmd_argv_ftype mi_cmd_stack_list_locals;
|
||||
extern mi_cmd_argv_ftype mi_cmd_stack_select_frame;
|
||||
extern mi_cmd_argv_ftype mi_cmd_symbol_list_lines;
|
||||
extern mi_cmd_args_ftype mi_cmd_target_download;
|
||||
extern mi_cmd_argv_ftype mi_cmd_target_file_get;
|
||||
extern mi_cmd_argv_ftype mi_cmd_target_file_put;
|
||||
extern mi_cmd_argv_ftype mi_cmd_target_file_delete;
|
||||
extern mi_cmd_args_ftype mi_cmd_target_select;
|
||||
extern mi_cmd_argv_ftype mi_cmd_thread_list_ids;
|
||||
extern mi_cmd_argv_ftype mi_cmd_thread_select;
|
||||
|
668
gdb/remote.c
668
gdb/remote.c
@ -58,6 +58,7 @@
|
||||
#include "gdbcore.h" /* for exec_bfd */
|
||||
|
||||
#include "remote-fileio.h"
|
||||
#include "gdb/fileio.h"
|
||||
|
||||
#include "memory-map.h"
|
||||
|
||||
@ -207,6 +208,10 @@ static void show_remote_protocol_packet_cmd (struct ui_file *file,
|
||||
|
||||
void _initialize_remote (void);
|
||||
|
||||
/* For "remote". */
|
||||
|
||||
static struct cmd_list_element *remote_cmdlist;
|
||||
|
||||
/* For "set remote" and "show remote". */
|
||||
|
||||
static struct cmd_list_element *remote_set_cmdlist;
|
||||
@ -901,6 +906,11 @@ enum {
|
||||
PACKET_Z2,
|
||||
PACKET_Z3,
|
||||
PACKET_Z4,
|
||||
PACKET_vFile_open,
|
||||
PACKET_vFile_pread,
|
||||
PACKET_vFile_pwrite,
|
||||
PACKET_vFile_close,
|
||||
PACKET_vFile_unlink,
|
||||
PACKET_qXfer_auxv,
|
||||
PACKET_qXfer_features,
|
||||
PACKET_qXfer_libraries,
|
||||
@ -6276,6 +6286,631 @@ remote_read_description (struct target_ops *target)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remote file transfer support. This is host-initiated I/O, not
|
||||
target-initiated; for target-initiated, see remote-fileio.c. */
|
||||
|
||||
/* If *LEFT is at least the length of STRING, copy STRING to
|
||||
*BUFFER, update *BUFFER to point to the new end of the buffer, and
|
||||
decrease *LEFT. Otherwise raise an error. */
|
||||
|
||||
static void
|
||||
remote_buffer_add_string (char **buffer, int *left, char *string)
|
||||
{
|
||||
int len = strlen (string);
|
||||
|
||||
if (len > *left)
|
||||
error (_("Packet too long for target."));
|
||||
|
||||
memcpy (*buffer, string, len);
|
||||
*buffer += len;
|
||||
*left -= len;
|
||||
|
||||
/* NUL-terminate the buffer as a convenience, if there is
|
||||
room. */
|
||||
if (*left)
|
||||
**buffer = '\0';
|
||||
}
|
||||
|
||||
/* If *LEFT is large enough, hex encode LEN bytes from BYTES into
|
||||
*BUFFER, update *BUFFER to point to the new end of the buffer, and
|
||||
decrease *LEFT. Otherwise raise an error. */
|
||||
|
||||
static void
|
||||
remote_buffer_add_bytes (char **buffer, int *left, const gdb_byte *bytes,
|
||||
int len)
|
||||
{
|
||||
if (2 * len > *left)
|
||||
error (_("Packet too long for target."));
|
||||
|
||||
bin2hex (bytes, *buffer, len);
|
||||
*buffer += 2 * len;
|
||||
*left -= 2 * len;
|
||||
|
||||
/* NUL-terminate the buffer as a convenience, if there is
|
||||
room. */
|
||||
if (*left)
|
||||
**buffer = '\0';
|
||||
}
|
||||
|
||||
/* If *LEFT is large enough, convert VALUE to hex and add it to
|
||||
*BUFFER, update *BUFFER to point to the new end of the buffer, and
|
||||
decrease *LEFT. Otherwise raise an error. */
|
||||
|
||||
static void
|
||||
remote_buffer_add_int (char **buffer, int *left, ULONGEST value)
|
||||
{
|
||||
int len = hexnumlen (value);
|
||||
|
||||
if (len > *left)
|
||||
error (_("Packet too long for target."));
|
||||
|
||||
hexnumstr (*buffer, value);
|
||||
*buffer += len;
|
||||
*left -= len;
|
||||
|
||||
/* NUL-terminate the buffer as a convenience, if there is
|
||||
room. */
|
||||
if (*left)
|
||||
**buffer = '\0';
|
||||
}
|
||||
|
||||
/* Parse an I/O result packet from BUFFER. Set RETCODE to the return
|
||||
value, *REMOTE_ERRNO to the remote error number or zero if none
|
||||
was included, and *ATTACHMENT to point to the start of the annex
|
||||
if any. The length of the packet isn't needed here; there may
|
||||
be NUL bytes in BUFFER, but they will be after *ATTACHMENT.
|
||||
|
||||
Return 0 if the packet could be parsed, -1 if it could not. If
|
||||
-1 is returned, the other variables may not be initialized. */
|
||||
|
||||
static int
|
||||
remote_hostio_parse_result (char *buffer, int *retcode,
|
||||
int *remote_errno, char **attachment)
|
||||
{
|
||||
char *p, *p2;
|
||||
|
||||
*remote_errno = 0;
|
||||
*attachment = NULL;
|
||||
|
||||
if (buffer[0] != 'F')
|
||||
return -1;
|
||||
|
||||
errno = 0;
|
||||
*retcode = strtol (&buffer[1], &p, 16);
|
||||
if (errno != 0 || p == &buffer[1])
|
||||
return -1;
|
||||
|
||||
/* Check for ",errno". */
|
||||
if (*p == ',')
|
||||
{
|
||||
errno = 0;
|
||||
*remote_errno = strtol (p + 1, &p2, 16);
|
||||
if (errno != 0 || p + 1 == p2)
|
||||
return -1;
|
||||
p = p2;
|
||||
}
|
||||
|
||||
/* Check for ";attachment". If there is no attachment, the
|
||||
packet should end here. */
|
||||
if (*p == ';')
|
||||
{
|
||||
*attachment = p + 1;
|
||||
return 0;
|
||||
}
|
||||
else if (*p == '\0')
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send a prepared I/O packet to the target and read its response.
|
||||
The prepared packet is in the global RS->BUF before this function
|
||||
is called, and the answer is there when we return.
|
||||
|
||||
COMMAND_BYTES is the length of the request to send, which may include
|
||||
binary data. WHICH_PACKET is the packet configuration to check
|
||||
before attempting a packet. If an error occurs, *REMOTE_ERRNO
|
||||
is set to the error number and -1 is returned. Otherwise the value
|
||||
returned by the function is returned.
|
||||
|
||||
ATTACHMENT and ATTACHMENT_LEN should be non-NULL if and only if an
|
||||
attachment is expected; an error will be reported if there's a
|
||||
mismatch. If one is found, *ATTACHMENT will be set to point into
|
||||
the packet buffer and *ATTACHMENT_LEN will be set to the
|
||||
attachment's length. */
|
||||
|
||||
static int
|
||||
remote_hostio_send_command (int command_bytes, int which_packet,
|
||||
int *remote_errno, char **attachment,
|
||||
int *attachment_len)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
int ret, bytes_read;
|
||||
char *attachment_tmp;
|
||||
|
||||
if (remote_protocol_packets[which_packet].support == PACKET_DISABLE)
|
||||
{
|
||||
*remote_errno = FILEIO_ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
putpkt_binary (rs->buf, command_bytes);
|
||||
bytes_read = getpkt_sane (&rs->buf, &rs->buf_size, 0);
|
||||
|
||||
/* If it timed out, something is wrong. Don't try to parse the
|
||||
buffer. */
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
*remote_errno = FILEIO_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (packet_ok (rs->buf, &remote_protocol_packets[which_packet]))
|
||||
{
|
||||
case PACKET_ERROR:
|
||||
*remote_errno = FILEIO_EINVAL;
|
||||
return -1;
|
||||
case PACKET_UNKNOWN:
|
||||
*remote_errno = FILEIO_ENOSYS;
|
||||
return -1;
|
||||
case PACKET_OK:
|
||||
break;
|
||||
}
|
||||
|
||||
if (remote_hostio_parse_result (rs->buf, &ret, remote_errno,
|
||||
&attachment_tmp))
|
||||
{
|
||||
*remote_errno = FILEIO_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure we saw an attachment if and only if we expected one. */
|
||||
if ((attachment_tmp == NULL && attachment != NULL)
|
||||
|| (attachment_tmp != NULL && attachment == NULL))
|
||||
{
|
||||
*remote_errno = FILEIO_EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If an attachment was found, it must point into the packet buffer;
|
||||
work out how many bytes there were. */
|
||||
if (attachment_tmp != NULL)
|
||||
{
|
||||
*attachment = attachment_tmp;
|
||||
*attachment_len = bytes_read - (*attachment - rs->buf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Open FILENAME on the remote target, using FLAGS and MODE. Return a
|
||||
remote file descriptor, or -1 if an error occurs (and set
|
||||
*REMOTE_ERRNO). */
|
||||
|
||||
static int
|
||||
remote_hostio_open (const char *filename, int flags, int mode,
|
||||
int *remote_errno)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
char *p = rs->buf;
|
||||
int left = get_remote_packet_size () - 1;
|
||||
|
||||
remote_buffer_add_string (&p, &left, "vFile:open:");
|
||||
|
||||
remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
|
||||
strlen (filename));
|
||||
remote_buffer_add_string (&p, &left, ",");
|
||||
|
||||
remote_buffer_add_int (&p, &left, flags);
|
||||
remote_buffer_add_string (&p, &left, ",");
|
||||
|
||||
remote_buffer_add_int (&p, &left, mode);
|
||||
|
||||
return remote_hostio_send_command (p - rs->buf, PACKET_vFile_open,
|
||||
remote_errno, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Write up to LEN bytes from WRITE_BUF to FD on the remote target.
|
||||
Return the number of bytes written, or -1 if an error occurs (and
|
||||
set *REMOTE_ERRNO). */
|
||||
|
||||
static int
|
||||
remote_hostio_pwrite (int fd, const gdb_byte *write_buf, int len,
|
||||
ULONGEST offset, int *remote_errno)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
char *p = rs->buf;
|
||||
int left = get_remote_packet_size ();
|
||||
int out_len;
|
||||
|
||||
remote_buffer_add_string (&p, &left, "vFile:pwrite:");
|
||||
|
||||
remote_buffer_add_int (&p, &left, fd);
|
||||
remote_buffer_add_string (&p, &left, ",");
|
||||
|
||||
remote_buffer_add_int (&p, &left, offset);
|
||||
remote_buffer_add_string (&p, &left, ",");
|
||||
|
||||
p += remote_escape_output (write_buf, len, p, &out_len,
|
||||
get_remote_packet_size () - (p - rs->buf));
|
||||
|
||||
return remote_hostio_send_command (p - rs->buf, PACKET_vFile_pwrite,
|
||||
remote_errno, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Read up to LEN bytes FD on the remote target into READ_BUF
|
||||
Return the number of bytes read, or -1 if an error occurs (and
|
||||
set *REMOTE_ERRNO). */
|
||||
|
||||
static int
|
||||
remote_hostio_pread (int fd, gdb_byte *read_buf, int len,
|
||||
ULONGEST offset, int *remote_errno)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
char *p = rs->buf;
|
||||
char *attachment;
|
||||
int left = get_remote_packet_size ();
|
||||
int ret, attachment_len;
|
||||
int read_len;
|
||||
|
||||
remote_buffer_add_string (&p, &left, "vFile:pread:");
|
||||
|
||||
remote_buffer_add_int (&p, &left, fd);
|
||||
remote_buffer_add_string (&p, &left, ",");
|
||||
|
||||
remote_buffer_add_int (&p, &left, len);
|
||||
remote_buffer_add_string (&p, &left, ",");
|
||||
|
||||
remote_buffer_add_int (&p, &left, offset);
|
||||
|
||||
ret = remote_hostio_send_command (p - rs->buf, PACKET_vFile_pread,
|
||||
remote_errno, &attachment,
|
||||
&attachment_len);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
read_len = remote_unescape_input (attachment, attachment_len,
|
||||
read_buf, len);
|
||||
if (read_len != ret)
|
||||
error (_("Read returned %d, but %d bytes."), ret, (int) read_len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Close FD on the remote target. Return 0, or -1 if an error occurs
|
||||
(and set *REMOTE_ERRNO). */
|
||||
|
||||
static int
|
||||
remote_hostio_close (int fd, int *remote_errno)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
char *p = rs->buf;
|
||||
int left = get_remote_packet_size () - 1;
|
||||
|
||||
remote_buffer_add_string (&p, &left, "vFile:close:");
|
||||
|
||||
remote_buffer_add_int (&p, &left, fd);
|
||||
|
||||
return remote_hostio_send_command (p - rs->buf, PACKET_vFile_close,
|
||||
remote_errno, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Unlink FILENAME on the remote target. Return 0, or -1 if an error
|
||||
occurs (and set *REMOTE_ERRNO). */
|
||||
|
||||
static int
|
||||
remote_hostio_unlink (const char *filename, int *remote_errno)
|
||||
{
|
||||
struct remote_state *rs = get_remote_state ();
|
||||
char *p = rs->buf;
|
||||
int left = get_remote_packet_size () - 1;
|
||||
|
||||
remote_buffer_add_string (&p, &left, "vFile:unlink:");
|
||||
|
||||
remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
|
||||
strlen (filename));
|
||||
|
||||
return remote_hostio_send_command (p - rs->buf, PACKET_vFile_unlink,
|
||||
remote_errno, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
remote_fileio_errno_to_host (int errnum)
|
||||
{
|
||||
switch (errnum)
|
||||
{
|
||||
case FILEIO_EPERM:
|
||||
return EPERM;
|
||||
case FILEIO_ENOENT:
|
||||
return ENOENT;
|
||||
case FILEIO_EINTR:
|
||||
return EINTR;
|
||||
case FILEIO_EIO:
|
||||
return EIO;
|
||||
case FILEIO_EBADF:
|
||||
return EBADF;
|
||||
case FILEIO_EACCES:
|
||||
return EACCES;
|
||||
case FILEIO_EFAULT:
|
||||
return EFAULT;
|
||||
case FILEIO_EBUSY:
|
||||
return EBUSY;
|
||||
case FILEIO_EEXIST:
|
||||
return EEXIST;
|
||||
case FILEIO_ENODEV:
|
||||
return ENODEV;
|
||||
case FILEIO_ENOTDIR:
|
||||
return ENOTDIR;
|
||||
case FILEIO_EISDIR:
|
||||
return EISDIR;
|
||||
case FILEIO_EINVAL:
|
||||
return EINVAL;
|
||||
case FILEIO_ENFILE:
|
||||
return ENFILE;
|
||||
case FILEIO_EMFILE:
|
||||
return EMFILE;
|
||||
case FILEIO_EFBIG:
|
||||
return EFBIG;
|
||||
case FILEIO_ENOSPC:
|
||||
return ENOSPC;
|
||||
case FILEIO_ESPIPE:
|
||||
return ESPIPE;
|
||||
case FILEIO_EROFS:
|
||||
return EROFS;
|
||||
case FILEIO_ENOSYS:
|
||||
return ENOSYS;
|
||||
case FILEIO_ENAMETOOLONG:
|
||||
return ENAMETOOLONG;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *
|
||||
remote_hostio_error (int errnum)
|
||||
{
|
||||
int host_error = remote_fileio_errno_to_host (errnum);
|
||||
|
||||
if (host_error == -1)
|
||||
error (_("Unknown remote I/O error %d"), errnum);
|
||||
else
|
||||
error (_("Remote I/O error: %s"), safe_strerror (host_error));
|
||||
}
|
||||
|
||||
static void
|
||||
fclose_cleanup (void *file)
|
||||
{
|
||||
fclose (file);
|
||||
}
|
||||
|
||||
static void
|
||||
remote_hostio_close_cleanup (void *opaque)
|
||||
{
|
||||
int fd = *(int *) opaque;
|
||||
int remote_errno;
|
||||
|
||||
remote_hostio_close (fd, &remote_errno);
|
||||
}
|
||||
|
||||
void
|
||||
remote_file_put (const char *local_file, const char *remote_file, int from_tty)
|
||||
{
|
||||
struct cleanup *back_to, *close_cleanup;
|
||||
int retcode, fd, remote_errno, bytes, io_size;
|
||||
FILE *file;
|
||||
gdb_byte *buffer;
|
||||
int bytes_in_buffer;
|
||||
int saw_eof;
|
||||
ULONGEST offset;
|
||||
|
||||
if (!remote_desc)
|
||||
error (_("command can only be used with remote target"));
|
||||
|
||||
file = fopen (local_file, "rb");
|
||||
if (file == NULL)
|
||||
perror_with_name (local_file);
|
||||
back_to = make_cleanup (fclose_cleanup, file);
|
||||
|
||||
fd = remote_hostio_open (remote_file, (FILEIO_O_WRONLY | FILEIO_O_CREAT
|
||||
| FILEIO_O_TRUNC),
|
||||
0700, &remote_errno);
|
||||
if (fd == -1)
|
||||
remote_hostio_error (remote_errno);
|
||||
|
||||
/* Send up to this many bytes at once. They won't all fit in the
|
||||
remote packet limit, so we'll transfer slightly fewer. */
|
||||
io_size = get_remote_packet_size ();
|
||||
buffer = xmalloc (io_size);
|
||||
make_cleanup (xfree, buffer);
|
||||
|
||||
close_cleanup = make_cleanup (remote_hostio_close_cleanup, &fd);
|
||||
|
||||
bytes_in_buffer = 0;
|
||||
saw_eof = 0;
|
||||
offset = 0;
|
||||
while (bytes_in_buffer || !saw_eof)
|
||||
{
|
||||
if (!saw_eof)
|
||||
{
|
||||
bytes = fread (buffer + bytes_in_buffer, 1, io_size - bytes_in_buffer,
|
||||
file);
|
||||
if (bytes == 0)
|
||||
{
|
||||
if (ferror (file))
|
||||
error (_("Error reading %s."), local_file);
|
||||
else
|
||||
{
|
||||
/* EOF. Unless there is something still in the
|
||||
buffer from the last iteration, we are done. */
|
||||
saw_eof = 1;
|
||||
if (bytes_in_buffer == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
bytes = 0;
|
||||
|
||||
bytes += bytes_in_buffer;
|
||||
bytes_in_buffer = 0;
|
||||
|
||||
retcode = remote_hostio_pwrite (fd, buffer, bytes, offset, &remote_errno);
|
||||
|
||||
if (retcode < 0)
|
||||
remote_hostio_error (remote_errno);
|
||||
else if (retcode == 0)
|
||||
error (_("Remote write of %d bytes returned 0!"), bytes);
|
||||
else if (retcode < bytes)
|
||||
{
|
||||
/* Short write. Save the rest of the read data for the next
|
||||
write. */
|
||||
bytes_in_buffer = bytes - retcode;
|
||||
memmove (buffer, buffer + retcode, bytes_in_buffer);
|
||||
}
|
||||
|
||||
offset += retcode;
|
||||
}
|
||||
|
||||
discard_cleanups (close_cleanup);
|
||||
if (remote_hostio_close (fd, &remote_errno))
|
||||
remote_hostio_error (remote_errno);
|
||||
|
||||
if (from_tty)
|
||||
printf_filtered (_("Successfully sent file \"%s\".\n"), local_file);
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
void
|
||||
remote_file_get (const char *remote_file, const char *local_file, int from_tty)
|
||||
{
|
||||
struct cleanup *back_to, *close_cleanup;
|
||||
int retcode, fd, remote_errno, bytes, io_size;
|
||||
FILE *file;
|
||||
gdb_byte *buffer;
|
||||
ULONGEST offset;
|
||||
|
||||
if (!remote_desc)
|
||||
error (_("command can only be used with remote target"));
|
||||
|
||||
fd = remote_hostio_open (remote_file, FILEIO_O_RDONLY, 0, &remote_errno);
|
||||
if (fd == -1)
|
||||
remote_hostio_error (remote_errno);
|
||||
|
||||
file = fopen (local_file, "wb");
|
||||
if (file == NULL)
|
||||
perror_with_name (local_file);
|
||||
back_to = make_cleanup (fclose_cleanup, file);
|
||||
|
||||
/* Send up to this many bytes at once. They won't all fit in the
|
||||
remote packet limit, so we'll transfer slightly fewer. */
|
||||
io_size = get_remote_packet_size ();
|
||||
buffer = xmalloc (io_size);
|
||||
make_cleanup (xfree, buffer);
|
||||
|
||||
close_cleanup = make_cleanup (remote_hostio_close_cleanup, &fd);
|
||||
|
||||
offset = 0;
|
||||
while (1)
|
||||
{
|
||||
bytes = remote_hostio_pread (fd, buffer, io_size, offset, &remote_errno);
|
||||
if (bytes == 0)
|
||||
/* Success, but no bytes, means end-of-file. */
|
||||
break;
|
||||
if (bytes == -1)
|
||||
remote_hostio_error (remote_errno);
|
||||
|
||||
offset += bytes;
|
||||
|
||||
bytes = fwrite (buffer, 1, bytes, file);
|
||||
if (bytes == 0)
|
||||
perror_with_name (local_file);
|
||||
}
|
||||
|
||||
discard_cleanups (close_cleanup);
|
||||
if (remote_hostio_close (fd, &remote_errno))
|
||||
remote_hostio_error (remote_errno);
|
||||
|
||||
if (from_tty)
|
||||
printf_filtered (_("Successfully fetched file \"%s\".\n"), remote_file);
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
void
|
||||
remote_file_delete (const char *remote_file, int from_tty)
|
||||
{
|
||||
int retcode, remote_errno;
|
||||
|
||||
if (!remote_desc)
|
||||
error (_("command can only be used with remote target"));
|
||||
|
||||
retcode = remote_hostio_unlink (remote_file, &remote_errno);
|
||||
if (retcode == -1)
|
||||
remote_hostio_error (remote_errno);
|
||||
|
||||
if (from_tty)
|
||||
printf_filtered (_("Successfully deleted file \"%s\".\n"), remote_file);
|
||||
}
|
||||
|
||||
static void
|
||||
remote_put_command (char *args, int from_tty)
|
||||
{
|
||||
struct cleanup *back_to;
|
||||
char **argv;
|
||||
|
||||
argv = buildargv (args);
|
||||
if (argv == NULL)
|
||||
nomem (0);
|
||||
back_to = make_cleanup_freeargv (argv);
|
||||
if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
|
||||
error (_("Invalid parameters to remote put"));
|
||||
|
||||
remote_file_put (argv[0], argv[1], from_tty);
|
||||
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
static void
|
||||
remote_get_command (char *args, int from_tty)
|
||||
{
|
||||
struct cleanup *back_to;
|
||||
char **argv;
|
||||
|
||||
argv = buildargv (args);
|
||||
if (argv == NULL)
|
||||
nomem (0);
|
||||
back_to = make_cleanup_freeargv (argv);
|
||||
if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
|
||||
error (_("Invalid parameters to remote get"));
|
||||
|
||||
remote_file_get (argv[0], argv[1], from_tty);
|
||||
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
static void
|
||||
remote_delete_command (char *args, int from_tty)
|
||||
{
|
||||
struct cleanup *back_to;
|
||||
char **argv;
|
||||
|
||||
argv = buildargv (args);
|
||||
if (argv == NULL)
|
||||
nomem (0);
|
||||
back_to = make_cleanup_freeargv (argv);
|
||||
if (argv[0] == NULL || argv[1] != NULL)
|
||||
error (_("Invalid parameters to remote delete"));
|
||||
|
||||
remote_file_delete (argv[0], from_tty);
|
||||
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
static void
|
||||
remote_command (char *args, int from_tty)
|
||||
{
|
||||
help_list (remote_cmdlist, "remote ", -1, gdb_stdout);
|
||||
}
|
||||
|
||||
static void
|
||||
init_remote_ops (void)
|
||||
{
|
||||
@ -6719,6 +7354,21 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qSupported],
|
||||
"qSupported", "supported-packets", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_open],
|
||||
"vFile:open", "hostio-open", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_pread],
|
||||
"vFile:pread", "hostio-pread", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_pwrite],
|
||||
"vFile:pwrite", "hostio-pwrite", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_close],
|
||||
"vFile:close", "hostio-close", 0);
|
||||
|
||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_unlink],
|
||||
"vFile:unlink", "hostio-unlink", 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
|
||||
@ -6733,6 +7383,24 @@ packets."),
|
||||
show_remote_protocol_Z_packet_cmd, /* FIXME: i18n: Use of remote protocol `Z' packets is %s. */
|
||||
&remote_set_cmdlist, &remote_show_cmdlist);
|
||||
|
||||
add_prefix_cmd ("remote", class_files, remote_command, _("\
|
||||
Manipulate files on the remote system\n\
|
||||
Transfer files to and from the remote target system."),
|
||||
&remote_cmdlist, "remote ",
|
||||
0 /* allow-unknown */, &cmdlist);
|
||||
|
||||
add_cmd ("put", class_files, remote_put_command,
|
||||
_("Copy a local file to the remote system."),
|
||||
&remote_cmdlist);
|
||||
|
||||
add_cmd ("get", class_files, remote_get_command,
|
||||
_("Copy a remote file to the local system."),
|
||||
&remote_cmdlist);
|
||||
|
||||
add_cmd ("delete", class_files, remote_delete_command,
|
||||
_("Delete a remote file."),
|
||||
&remote_cmdlist);
|
||||
|
||||
/* Eventually initialize fileio. See fileio.c */
|
||||
initialize_remote_fileio (remote_set_cmdlist, remote_show_cmdlist);
|
||||
}
|
||||
|
@ -67,4 +67,10 @@ extern void (*deprecated_target_wait_loop_hook) (void);
|
||||
void register_remote_g_packet_guess (struct gdbarch *gdbarch, int bytes,
|
||||
const struct target_desc *tdesc);
|
||||
|
||||
void remote_file_put (const char *local_file, const char *remote_file,
|
||||
int from_tty);
|
||||
void remote_file_get (const char *remote_file, const char *local_file,
|
||||
int from_tty);
|
||||
void remote_file_delete (const char *remote_file, int from_tty);
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,8 @@
|
||||
2007-11-30 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* gdb.server/file-transfer.exp, gdb.server/transfer.txt,
|
||||
gdb.mi/mi-file-transfer.exp: New.
|
||||
|
||||
2007-11-25 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||
|
||||
* gdb.dwarf2/dw2-ranges.S, gdb.dwarf2/dw2-ranges.exp: New files.
|
||||
|
99
gdb/testsuite/gdb.mi/mi-file-transfer.exp
Normal file
99
gdb/testsuite/gdb.mi/mi-file-transfer.exp
Normal file
@ -0,0 +1,99 @@
|
||||
# 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 gdbserver monitor commands.
|
||||
|
||||
load_lib gdbserver-support.exp
|
||||
load_lib mi-support.exp
|
||||
set MIFLAGS "-i=mi"
|
||||
|
||||
if { [skip_gdbserver_tests] } {
|
||||
return 0
|
||||
}
|
||||
|
||||
set testfile "basics"
|
||||
set srcfile ${testfile}.c
|
||||
set binfile ${objdir}/${subdir}/${testfile}
|
||||
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
|
||||
untested mi-file-transfer.exp
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_exit
|
||||
if [mi_gdb_start] {
|
||||
continue
|
||||
}
|
||||
mi_delete_breakpoints
|
||||
mi_gdb_reinitialize_dir $srcdir/$subdir
|
||||
mi_gdb_file_cmd ${binfile}
|
||||
|
||||
proc mi_gdbserver_run { } {
|
||||
mi_gdb_test "kill" ".*" ""
|
||||
|
||||
set res [gdbserver_spawn ""]
|
||||
set protocol [lindex $res 0]
|
||||
set gdbport [lindex $res 1]
|
||||
|
||||
if { [mi_gdb_target_cmd $protocol $gdbport] != 0 } {
|
||||
return -1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
proc test_file_transfer { filename description } {
|
||||
mi_gdb_test "-target-file-put \"$filename\" \"down-server\"" \
|
||||
"\\^done" "put $description"
|
||||
mi_gdb_test "-target-file-get \"down-server\" \"up-server\"" \
|
||||
"\\^done" "get $description"
|
||||
|
||||
if { ![is_remote target] } {
|
||||
# If we can check the target copy of the file, do that too.
|
||||
# This should catch symmetric errors in upload and download.
|
||||
set result [remote_exec host "cmp -s $filename down-server"]
|
||||
if { [lindex $result 0] == 0 } {
|
||||
pass "compare intermediate $description"
|
||||
} else {
|
||||
fail "compare intermediate $description"
|
||||
}
|
||||
}
|
||||
|
||||
set result [remote_exec host "cmp -s $filename up-server"]
|
||||
if { [lindex $result 0] == 0 } {
|
||||
pass "compare $description"
|
||||
} else {
|
||||
fail "compare $description"
|
||||
}
|
||||
|
||||
mi_gdb_test "-target-file-delete \"down-server\"" \
|
||||
"\\^done" "deleted $description"
|
||||
|
||||
if { ![is_remote target] } {
|
||||
if { ! [remote_file target exists down-server] } {
|
||||
pass "verified deleted $description"
|
||||
} else {
|
||||
fail "verified deleted $description"
|
||||
}
|
||||
}
|
||||
|
||||
catch { file delete up-server }
|
||||
}
|
||||
|
||||
mi_gdbserver_run
|
||||
|
||||
test_file_transfer "$binfile" "binary file"
|
||||
|
||||
mi_gdb_exit
|
80
gdb/testsuite/gdb.server/file-transfer.exp
Normal file
80
gdb/testsuite/gdb.server/file-transfer.exp
Normal file
@ -0,0 +1,80 @@
|
||||
# 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 gdbserver monitor commands.
|
||||
|
||||
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}] != "" } {
|
||||
untested file-transfer.exp
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_exit
|
||||
gdb_start
|
||||
gdb_load $binfile
|
||||
gdb_reinitialize_dir $srcdir/$subdir
|
||||
|
||||
gdbserver_run ""
|
||||
|
||||
proc test_file_transfer { filename description } {
|
||||
gdb_test "remote put \"$filename\" down-server" \
|
||||
"Successfully sent .*" "put $description"
|
||||
gdb_test "remote get down-server up-server" \
|
||||
"Successfully fetched .*" "get $description"
|
||||
|
||||
if { ![is_remote target] } {
|
||||
# If we can check the target copy of the file, do that too.
|
||||
# This should catch symmetric errors in upload and download.
|
||||
set result [remote_exec host "cmp -s $filename down-server"]
|
||||
if { [lindex $result 0] == 0 } {
|
||||
pass "compare intermediate $description"
|
||||
} else {
|
||||
fail "compare intermediate $description"
|
||||
}
|
||||
}
|
||||
|
||||
set result [remote_exec host "cmp -s $filename up-server"]
|
||||
if { [lindex $result 0] == 0 } {
|
||||
pass "compare $description"
|
||||
} else {
|
||||
fail "compare $description"
|
||||
}
|
||||
|
||||
gdb_test "remote delete down-server" \
|
||||
"Successfully deleted .*" "deleted $description"
|
||||
|
||||
if { ![is_remote target] } {
|
||||
if { ! [remote_file target exists down-server] } {
|
||||
pass "verified deleted $description"
|
||||
} else {
|
||||
fail "verified deleted $description"
|
||||
}
|
||||
}
|
||||
|
||||
catch { file delete up-server }
|
||||
}
|
||||
|
||||
test_file_transfer "$binfile" "binary file"
|
||||
test_file_transfer "$srcdir/$subdir/transfer.txt" "text file"
|
12
gdb/testsuite/gdb.server/transfer.txt
Normal file
12
gdb/testsuite/gdb.server/transfer.txt
Normal file
@ -0,0 +1,12 @@
|
||||
This text file is a test input for GDB's file transfer commands. It
|
||||
contains some characters which need to be escaped in remote protocol
|
||||
packets, like "*" and "}" and "$" and "#". Actually, it contains
|
||||
a good sampling of printable characters:
|
||||
|
||||
!"#$%&'()*+,-./0123456789:;<=>?@
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`
|
||||
abcdefghijklmnopqrstuvwxyz{|}~
|
||||
|
||||
!"#$%&'()*+,-./0123456789:;<=>?@
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`
|
||||
abcdefghijklmnopqrstuvwxyz{|}~
|
Reference in New Issue
Block a user