Re: [RFA] New commands, dump/restore memory<-->file

Michael Snyder
2002-03-29T01:24:33Z

[-- Attachment #1: Type: text/plain, Size: 1144 bytes --]

Michael Snyder wrote:
>
> Hello,
>
> Back in January, there was a discussion about adding commands that
> would allow gdb to copy data from target memory to a file and back
> again. Andrew and I have done an implementation of those commands,
> and here it is for your approval.
>
> The syntax looks like this:
>
> dump <format> <filename> memory <start> <end>
> dump <format> <filename> value <expression>
> restore <filename> <offset> <start> <end>
>
> Where <format> may be srec, ihex, tekhex, or binary (defaulting
> to binary). Start and end may be numeric or symbolic.
> Expression can be any expression that GDB can normally evaluate.
>
> The restore command can copy a file back into target memory
> for any running target. It can bias the copy by an offset,
> and it can copy a subrange of the file (specified by start and
> end, which are file-relative ie. before the offset is applied).
>
> There is also an alternate form of the dump command called
> append, which will append new data onto an existing file;
> it only works with the binary file format at present.
>

Committed, with docs, and slight mods as shown below.

[-- Attachment #2: dump.patch --]
[-- Type: text/plain, Size: 70505 bytes --]

2002-03-26 Michael Snyder <msnyder@redhat.com>
Andrew Cagney <cagney@redhat.com>

* cli/cli-dump.c: New file. Dump memory to file,
restore file to memory.
* cli/cli-dump.h: New file.
* Makefile.in: Add rules, dependencies for cli-dump.o.

2002-03-27 Michael Snyder <msnyder@redhat.com>

* gdb.texinfo: Document new commands dump, append, and restore.

2002-03-26 Michael Snyder <msnyder@redhat.com>

* gdb.base/default.exp: Add tests for dump, append, and restore.
* gdb.base/help.exp: Add tests for dump, append, and restore.
* gdb.base/dump.exp: New file, test dump, append and restore.
* gdb.base/dump.c: New file.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.166
diff -c -3 -p -r1.166 Makefile.in
*** Makefile.in 2002/03/27 05:10:38 1.166
--- Makefile.in 2002/03/29 01:12:51
*************** INTL_CFLAGS = -I$(INTL_DIR) -I$(INTL_SRC
*** 137,144 ****
--- 137,146 ----
# CLI sub directory definitons
#
SUBDIR_CLI_OBS = \
+ cli-dump.o \
cli-decode.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o
SUBDIR_CLI_SRCS = \
+ cli/cli-dump.c \
cli/cli-decode.c cli/cli-script.c cli/cli-cmds.c cli/cli-setshow.c \
cli/cli-utils.c
SUBDIR_CLI_DEPS =
*************** c_lang_h = c-lang.h $(value_h)
*** 593,598 ****
--- 595,601 ----
call_cmds_h = call-cmds.h
cli_cmds_h = $(srcdir)/cli/cli-cmds.h
cli_decode_h = $(srcdir)/cli/cli-decode.h $(command_h)
+ cli_dump_h = $(srcdir)/cli/cli-dump.h
cli_out_h = cli-out.h
cli_script_h = $(srcdir)/cli/cli-script.h
cli_setshow_h = $(srcdir)/cli/cli-setshow.h
*************** wrapper.o: wrapper.c $(defs_h) $(frame_h
*** 2212,2226 ****
# Need to explicitly specify the compile rule as make will do nothing
# or try to compile the object file into the cli directory.

cli-decode.o: $(srcdir)/cli/cli-decode.c $(cli_decode_h) \
$(cli_cmds_h) $(defs_h) $(ui_out_h) \
$(symtab_h) gdb_regex.h
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-decode.c

! cli-cmds.o: $(srcdir)/cli/cli-cmds.c $(cli_cmds_h) $(cli_decode_h) \
! $(cli_script_h) $(cli_setshow_h) $(top_h) $(completer_h) \
! $(defs_h) $(target_h) gdb_wait.h gdb_regex.h $(ui_out_h)
! $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-cmds.c

cli-setshow.o: $(srcdir)/cli/cli-setshow.c $(cli_setshow_h) \
$(cli_decode_h) $(cli_cmds_h) $(defs_h) \
--- 2215,2233 ----
# Need to explicitly specify the compile rule as make will do nothing
# or try to compile the object file into the cli directory.

+ cli-cmds.o: $(srcdir)/cli/cli-cmds.c $(cli_cmds_h) $(cli_decode_h) \
+ $(cli_script_h) $(cli_setshow_h) $(top_h) $(completer_h) \
+ $(defs_h) $(target_h) gdb_wait.h gdb_regex.h $(ui_out_h)
+ $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-cmds.c
+
cli-decode.o: $(srcdir)/cli/cli-decode.c $(cli_decode_h) \
$(cli_cmds_h) $(defs_h) $(ui_out_h) \
$(symtab_h) gdb_regex.h
$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-decode.c

! cli-dump.o: $(srcdir)/cli/cli-dump.c $(defs_h) $(gdb_string_h) $(command_h) \
! $(value_h) $(gdbcmd_h) $(completer_h) $(cli_dump_h)
! $(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-dump.c

cli-setshow.o: $(srcdir)/cli/cli-setshow.c $(cli_setshow_h) \
$(cli_decode_h) $(cli_cmds_h) $(defs_h) \
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.59
diff -c -3 -p -r1.59 NEWS
*** NEWS 2002/03/05 22:57:57 1.59
--- NEWS 2002/03/29 01:13:51
***************
*** 3,8 ****
--- 3,13 ----

*** Changes since GDB 5.2:

+ * New commands "dump", "append", and "restore".
+
+ These commands allow data to be copied from target memory
+ to a bfd-format or binary file (dump and append), and back
+ from a file into memory (restore).

*** Changes in GDB 5.2:

Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.93
diff -c -3 -p -r1.93 gdb.texinfo
*** gdb.texinfo 2002/03/19 02:49:51 1.93
--- gdb.texinfo 2002/03/29 01:14:11
*************** Table}.
*** 4404,4409 ****
--- 4404,4410 ----
* Registers:: Registers
* Floating Point Hardware:: Floating point hardware
* Memory Region Attributes:: Memory region attributes
+ * Dump/Restore Files:: Copy between memory and a file
@end menu

@node Expressions
*************** the ARM and x86 machines.
*** 5567,5573 ****
@end table

@node Memory Region Attributes
! @section Memory Region Attributes
@cindex memory region attributes

@dfn{Memory region attributes} allow you to describe special handling
--- 5568,5574 ----
@end table

@node Memory Region Attributes
! @section Memory region attributes
@cindex memory region attributes

@dfn{Memory region attributes} allow you to describe special handling
*************** Disable @value{GDBN} from caching target
*** 5696,5701 ****
--- 5697,5778 ----
@c @item verify
@c @item noverify (default)
@c @end table
+
+ @node Dump/Restore Files
+ @section Copy between memory and a file
+ @cindex dump/restore files
+ @cindex append data to a file
+ @cindex dump data to a file
+ @cindex restore data from a file
+ @kindex dump
+ @kindex append
+ @kindex restore
+
+ The commands @code{dump}, @code{append}, and @code{restore} are used
+ for copying data between target memory and a file. Data is written
+ into a file using @code{dump} or @code{append}, and restored from a
+ file into memory by using @code{restore}. Files may be binary, srec,
+ intel hex, or tekhex (but only binary files can be appended).
+
+ @table @code
+ @kindex dump binary
+ @kindex append binary
+ @item dump binary memory @var{filename} @var{start_addr} @var{end_addr}
+ Dump contents of memory from @var{start_addr} to @var{end_addr} into
+ raw binary format file @var{filename}.
+
+ @item append binary memory @var{filename} @var{start_addr} @var{end_addr}
+ Append contents of memory from @var{start_addr} to @var{end_addr} to
+ raw binary format file @var{filename}.
+
+ @item dump binary value @var{filename} @var{expression}
+ Dump value of @var{expression} into raw binary format file @var{filename}.
+
+ @item append binary memory @var{filename} @var{expression}
+ Append value of @var{expression} to raw binary format file @var{filename}.
+
+ @kindex dump ihex
+ @item dump ihex memory @var{filename} @var{start_addr} @var{end_addr}
+ Dump contents of memory from @var{start_addr} to @var{end_addr} into
+ intel hex format file @var{filename}.
+
+ @item dump ihex value @var{filename} @var{expression}
+ Dump value of @var{expression} into intel hex format file @var{filename}.
+
+ @kindex dump srec
+ @item dump srec memory @var{filename} @var{start_addr} @var{end_addr}
+ Dump contents of memory from @var{start_addr} to @var{end_addr} into
+ srec format file @var{filename}.
+
+ @item dump srec value @var{filename} @var{expression}
+ Dump value of @var{expression} into srec format file @var{filename}.
+
+ @kindex dump tekhex
+ @item dump tekhex memory @var{filename} @var{start_addr} @var{end_addr}
+ Dump contents of memory from @var{start_addr} to @var{end_addr} into
+ tekhex format file @var{filename}.
+
+ @item dump tekhex value @var{filename} @var{expression}
+ Dump value of @var{expression} into tekhex format file @var{filename}.
+
+ @item restore @var{filename} @var{[binary]} @var{bias} @var{start} @var{end}
+ Restore the contents of file @var{filename} into memory. The @code{restore}
+ command can automatically recognize any known bfd file format, except for
+ raw binary. To restore a raw binary file you must use the optional argument
+ @var{binary} after the filename.
+
+ If @var{bias} is non-zero, its value will be added to the addresses
+ contained in the file. Binary files always start at address zero, so
+ they will be restored at address @var{bias}. Other bfd files have
+ a built-in location; they will be restored at offset @var{bias}
+ from that location.
+
+ If @var{start} and/or @var{end} are non-zero, then only data between
+ file offset @var{start} and file offset @var{end} will be restored.
+ These offsets are relative to the addresses in the file, before
+ the @var{bias} argument is applied.
+
+ @end table

@node Tracepoints
@chapter Tracepoints
Index: testsuite/gdb.base/help.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/help.exp,v
retrieving revision 1.9
diff -c -3 -p -r1.9 help.exp
*** help.exp 2002/03/28 01:36:23 1.9
--- help.exp 2002/03/29 01:14:33
*************** gdb_test "set height 400" "" "test set h
*** 38,43 ****
--- 38,51 ----
gdb_test "help add-symbol-file" "Usage: add-symbol-file FILE ADDR \\\[-s <SECT> <SECT_ADDR> -s <SECT> <SECT_ADDR> \.\.\.\\\]\[\r\n\]+Load the symbols from FILE, assuming FILE has been dynamically loaded\.\[\r\n\]+ADDR is the starting address of the file's text\.\[\r\n\]+The optional arguments are section-name section-address pairs and\[\r\n\]+should be specified if the data and bss segments are not contiguous\[\r\n\]+with the text\. SECT is a section name to be loaded at SECT_ADDR\." "help add-symbol-file"
# test help aliases
gdb_test "help aliases" "Aliases of other commands\.\[\r\n\]+List of commands\:.*\[\r\n\]+Type \"help\" followed by command name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help aliases"
+ # test help append
+ gdb_test "help append" "Append target code/data to a local file\.\[\r\n\]+List of append subcommands:.*"
+ gdb_test "help append binary" "Append target code/data to a raw binary file\.\[\r\n\]+List of append binary subcommands:.*"
+ gdb_test "help append memory" "Append contents of memory to a raw binary file\.\[\r\n\]+Arguments are FILE START STOP\. Writes the contents of memory within the\[\r\n\]+range \\\[START \.\. STOP\\) to the specifed FILE in raw target ordered bytes\."
+ gdb_test "help append value" "Append the value of an expression to a raw binary file\.\[\r\n\]+Arguments are FILE EXPRESSION\. Writes the value of EXPRESSION to\[\r\n\]+the specified FILE in raw target ordered bytes\."
+ gdb_test "help append binary memory" "Append contents of memory to a raw binary file\.\[\r\n\]+Arguments are FILE START STOP\. Writes the contents of memory within the\[\r\n\]+range \\\[START \.\. STOP\\) to the specifed FILE in raw target ordered bytes\."
+ gdb_test "help append binary value" "Append the value of an expression to a raw binary file\.\[\r\n\]+Arguments are FILE EXPRESSION\. Writes the value of EXPRESSION\[\r\n\]+to the specified FILE in raw target ordered bytes\."
+ # test help attach
gdb_test "help attach" "Attach to a process or file outside of GDB\.\[\r\n\]+This command attaches to another target, of the same type as your last\[\r\n\]+\"target\" command \\(\"info files\" will show your target stack\\)\.\[\r\n\]+The command may take as argument a process id or a device file\.\[\r\n\]+For a process id, you must have permission to send the process a signal,\[\r\n\]+and it must have the same effective uid as the debugger\.\[\r\n\]+When using \"attach\" with a process id, the debugger finds the\[\r\n\]+program running in the process, looking first in the current working\[\r\n\]+directory, or \\(if not found there\\) using the source file search path\[\r\n\]+\\(see the \"directory\" command\\)\. You can also use the \"file\" command\[\r\n\]+to specify the program, and to load its symbol table\." "help attach"
# test help breakpoint "b" abbreviation
gdb_test "help b" "Set breakpoint at specified line or function\.\[\r\n\]+Argument may be line number, function name, or \"\[*\]\" and an address\.\[\r\n\]+If line number is specified, break at start of code for that line\.\[\r\n\]+If function is specified, break at start of code for that function\.\[\r\n\]+If an address is specified, break at that exact address\.\[\r\n\]+With no arg, uses current execution address of selected stack frame\.\[\r\n\]+This is useful for breaking on return to a stack frame\.\[\r\n\]+Multiple breakpoints at one place are permitted, and useful if conditional\.\[\r\n\]+Do \"help breakpoints\" for info on other commands dealing with breakpoints\." "help breakpoint \"b\" abbreviation"
*************** gdb_test "help document" "Document a use
*** 111,116 ****
--- 119,140 ----
gdb_test "help down" "Select and print stack frame called by this one\.\[\r\n\]+An argument says how many frames down to go\." "help down"
# test help down-silently
gdb_test "help down-silently" "Same as the `down' command, but does not print anything\.\[\r\n\]+This is useful in command scripts\." "help down-silently"
+ # test help dump
+ gdb_test "help dump" "Dump target code/data to a local file\.\[\r\n\]+List of dump subcommands:.*"
+ gdb_test "help dump binary" "Write target code/data to a raw binary file\.\[\r\n\]+List of dump binary subcommands:.*"
+ gdb_test "help dump ihex" "Write target code/data to an intel hex file\.\[\r\n\]+List of dump ihex subcommands:.*"
+ gdb_test "help dump memory" "Write contents of memory to a raw binary file\.\[\r\n\]+Arguments are FILE START STOP\. Writes the contents of memory within the\[\r\n\]+range \\\[START \.\. STOP\\) to the specifed FILE in raw target ordered bytes\."
+ gdb_test "help dump srec" "Write target code/data to an srec file\.\[\r\n\]+List of dump srec subcommands:.*"
+ gdb_test "help dump tekhex" "Write target code/data to a tekhex file\.\[\r\n\]+List of dump tekhex subcommands:.*"
+ gdb_test "help dump value" "Write the value of an expression to a raw binary file\.\[\r\n\]+Arguments are FILE EXPRESSION\. Writes the value of EXPRESSION to\[\r\n\]+the specified FILE in raw target ordered bytes\."
+ gdb_test "help dump binary memory" "Write contents of memory to a raw binary file\.\[\r\n\]+Arguments are FILE START STOP\. Writes the contents of memory\[\r\n\]+within the range \\\[START \.\. STOP\\) to the specifed FILE in binary format\."
+ gdb_test "help dump binary value" "Write the value of an expression to a raw binary file\.\[\r\n\]+Arguments are FILE EXPRESSION\. Writes the value of EXPRESSION\[\r\n\]+to the specified FILE in raw target ordered bytes\." "help dump binary value"
+ gdb_test "help dump ihex memory" "Write contents of memory to an ihex file\.\[\r\n\]+Arguments are FILE START STOP\. Writes the contents of memory within\[\r\n\]+the range \\\[START \.\. STOP\\) to the specifed FILE in intel hex format\."
+ gdb_test "help dump ihex value" "Write the value of an expression to an ihex file\.\[\r\n\]+Arguments are FILE EXPRESSION\. Writes the value of EXPRESSION\[\r\n\]+to the specified FILE in intel hex format\."
+ gdb_test "help dump srec memory" "Write contents of memory to an srec file\.\[\r\n\]+Arguments are FILE START STOP\. Writes the contents of memory\[\r\n\]+within the range \\\[START \.\. STOP\\) to the specifed FILE in srec format\."
+ gdb_test "help dump srec value" "Write the value of an expression to an srec file\.\[\r\n\]+Arguments are FILE EXPRESSION\. Writes the value of EXPRESSION\[\r\n\]+to the specified FILE in srec format\."
+ gdb_test "help dump tekhex memory" "Write contents of memory to a tekhex file\.\[\r\n\]+Arguments are FILE START STOP\. Writes the contents of memory\[\r\n\]+within the range \\\[START \.\. STOP\\) to the specifed FILE in tekhex format\."
+ gdb_test "help dump tekhex value" "Write the value of an expression to a tekhex file\.\[\r\n\]+Arguments are FILE EXPRESSION\. Writes the value of EXPRESSION\[\r\n\]+to the specified FILE in tekhex format\."
# this command was removed from GDB 4.5.8
# test help dump-me
#send_gdb "help dump-me"
*************** gdb_test "help r" "Start debugged progra
*** 298,303 ****
--- 322,329 ----
gdb_test "help run" "Start debugged program\. You may specify arguments to give it\.\[\r\n\]+Args may include \"\\*\", or \"\\\[\.\.\.\\\]\"; they are expanded using \"sh\"\.\[\r\n\]+Input and output redirection with \">\", \"<\", or \">>\" are also allowed\.\[\r\n\]+With no arguments, uses arguments last specified \\(with \"run\" or \"set args\"\\)\.\[\r\n\]+To cancel previous arguments and run with no arguments,\[\r\n\]+use \"set args\" without arguments\." "help run"
# test help rbreak
gdb_test "help rbreak" "Set a breakpoint for all functions matching REGEXP\." "help rbreak"
+ # test help restore
+ gdb_test "help restore" "Restore the contents of FILE to target memory\.\[\r\n\]+Arguments are FILE OFFSET START END where all except FILE are optional\.\[\r\n\]+OFFSET will be added to the base address of the file \\(default zero\\)\.\[\r\n\]+If START and END are given, only the file contents within that range\[\r\n\]+\\(file relative\\) will be restored to target memory\."
# test help return
gdb_test "help return" "Make selected stack frame return to its caller\.\[\r\n\]+Control remains in the debugger, but when you continue\[\r\n\]+execution will resume in the frame above the one now selected\.\[\r\n\]+If an argument is given, it is an expression for the value to return\." "help return"
# test help reverse-search
*************** gdb_test "help set annotate" "Set annota
*** 317,327 ****
# test help set args
gdb_test "help set args" "Set argument list to give program being debugged when it is started\.\[\r\n\]+Follow this command with any number of args, to be passed to the program\."
# test help set check "c" abbreviation
! gdb_test "help set c" "Set the status of the type/range checker.\[\r\n\]+List of set check subcommands:\[\r\n\]+set check range -- Set range checking\[\r\n\]+set check type -- Set type checking\[\r\n\]+Type \"help set check\" followed by set check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help set check \"c\" abbreviation"
# test help set check "ch" abbreviation
! gdb_test "help set ch" "Set the status of the type/range checker.\[\r\n\]+List of set check subcommands:\[\r\n\]+set check range -- Set range checking\[\r\n\]+set check type -- Set type checking\[\r\n\]+Type \"help set check\" followed by set check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help set check \"ch\" abbreviation"
# test help set check
! gdb_test "help set check" "Set the status of the type/range checker.\[\r\n\]+List of set check subcommands:\[\r\n\]+set check range -- Set range checking\[\r\n\]+set check type -- Set type checking\[\r\n\]+Type \"help set check\" followed by set check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help set check"
# test help set check range
gdb_test "help set check range" "Set range checking\. \\(on/warn/off/auto\\)" "help set check range"
# test help set check type
--- 343,353 ----
# test help set args
gdb_test "help set args" "Set argument list to give program being debugged when it is started\.\[\r\n\]+Follow this command with any number of args, to be passed to the program\."
# test help set check "c" abbreviation
! gdb_test "help set c" "Set the status of the type/range checker\.\[\r\n\]+List of set check subcommands:\[\r\n\]+set check range -- Set range checking\[\r\n\]+set check type -- Set type checking\[\r\n\]+Type \"help set check\" followed by set check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help set check \"c\" abbreviation"
# test help set check "ch" abbreviation
! gdb_test "help set ch" "Set the status of the type/range checker\.\[\r\n\]+List of set check subcommands:\[\r\n\]+set check range -- Set range checking\[\r\n\]+set check type -- Set type checking\[\r\n\]+Type \"help set check\" followed by set check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help set check \"ch\" abbreviation"
# test help set check
! gdb_test "help set check" "Set the status of the type/range checker\.\[\r\n\]+List of set check subcommands:\[\r\n\]+set check range -- Set range checking\[\r\n\]+set check type -- Set type checking\[\r\n\]+Type \"help set check\" followed by set check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help set check"
# test help set check range
gdb_test "help set check range" "Set range checking\. \\(on/warn/off/auto\\)" "help set check range"
# test help set check type
*************** gdb_test "help set height" "Set number o
*** 339,345 ****
# test help set history expansion
gdb_test "help set history expansion" "Set history expansion on command input\.\[\r\n\]+Without an argument, history expansion is enabled\." "help set history expansion"
# test help set history filename
! gdb_test "help set history filename" "Set the filename in which to record the command history\[\r\n\]+ \\(the list of previous commands of which a record is kept\\)\." "help set history filename"
# test help set history save
gdb_test "help set history save" "Set saving of the history record on exit\.\[\r\n\]+Use \"on\" to enable the saving, and \"off\" to disable it\.\[\r\n\]+Without an argument, saving is enabled\." "help set history save"
# test help set history size
--- 365,371 ----
# test help set history expansion
gdb_test "help set history expansion" "Set history expansion on command input\.\[\r\n\]+Without an argument, history expansion is enabled\." "help set history expansion"
# test help set history filename
! gdb_test "help set history filename" "Set the filename in which to record the command history\[\r\n\]+\\(the list of previous commands of which a record is kept\\)\." "help set history filename"
# test help set history save
gdb_test "help set history save" "Set saving of the history record on exit\.\[\r\n\]+Use \"on\" to enable the saving, and \"off\" to disable it\.\[\r\n\]+Without an argument, saving is enabled\." "help set history save"
# test help set history size
*************** gdb_test "help show annotate" "Show anno
*** 406,414 ****
# test help show args
gdb_test "help show args" "Show argument list to give program being debugged when it is started\.\[\r\n\]+Follow this command with any number of args, to be passed to the program\."
# test help show check "c" abbreviation
! gdb_test "help show c" "Show the status of the type/range checker.\[\r\n\]+List of show check subcommands:\[\r\n\]+show check range -- Show range checking\[\r\n\]+show check type -- Show type checking\[\r\n\]+Type \"help show check\" followed by show check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help show check \"c\" abbreviation"
# test help show check
! gdb_test "help show check" "Show the status of the type/range checker.\[\r\n\]+List of show check subcommands:\[\r\n\]+show check range -- Show range checking\[\r\n\]+show check type -- Show type checking\[\r\n\]+Type \"help show check\" followed by show check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help show check"
# test help show check range
gdb_test "help show check range" "Show range checking\. \\(on/warn/off/auto\\)" "help show check range"
# test help show check type
--- 432,440 ----
# test help show args
gdb_test "help show args" "Show argument list to give program being debugged when it is started\.\[\r\n\]+Follow this command with any number of args, to be passed to the program\."
# test help show check "c" abbreviation
! gdb_test "help show c" "Show the status of the type/range checker\.\[\r\n\]+List of show check subcommands:\[\r\n\]+show check range -- Show range checking\[\r\n\]+show check type -- Show type checking\[\r\n\]+Type \"help show check\" followed by show check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help show check \"c\" abbreviation"
# test help show check
! gdb_test "help show check" "Show the status of the type/range checker\.\[\r\n\]+List of show check subcommands:\[\r\n\]+show check range -- Show range checking\[\r\n\]+show check type -- Show type checking\[\r\n\]+Type \"help show check\" followed by show check subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help show check"
# test help show check range
gdb_test "help show check range" "Show range checking\. \\(on/warn/off/auto\\)" "help show check range"
# test help show check type
*************** gdb_test "help show history filename" "S
*** 436,442 ****
# test help show history save
gdb_test "help show history save" "Show saving of the history record on exit\.\[\r\n\]+Use \"on\" to enable the saving, and \"off\" to disable it\.\[\r\n\]+Without an argument, saving is enabled\." "help show history save"
# test help show history size
! gdb_test "help show history size" "Show the size of the command history, \[\r\n\]+ie\. the number of previous commands to keep a record of\." "help show history size"
# test help show history
gdb_test "help show history" "Generic command for showing command history parameters\.\[\r\n\]+List of show history subcommands:\[\r\n\]+show history expansion -- Show history expansion on command input\[\r\n\]+show history filename -- Show the filename in which to record the command history\[\r\n\]+show history save -- Show saving of the history record on exit\[\r\n\]+show history size -- Show the size of the command history\[\r\n\]+Type \"help show history\" followed by show history subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help show history"
# test help show language
--- 462,468 ----
# test help show history save
gdb_test "help show history save" "Show saving of the history record on exit\.\[\r\n\]+Use \"on\" to enable the saving, and \"off\" to disable it\.\[\r\n\]+Without an argument, saving is enabled\." "help show history save"
# test help show history size
! gdb_test "help show history size" "Show the size of the command history,\[\r\n\]+ie\. the number of previous commands to keep a record of\." "help show history size"
# test help show history
gdb_test "help show history" "Generic command for showing command history parameters\.\[\r\n\]+List of show history subcommands:\[\r\n\]+show history expansion -- Show history expansion on command input\[\r\n\]+show history filename -- Show the filename in which to record the command history\[\r\n\]+show history save -- Show saving of the history record on exit\[\r\n\]+show history size -- Show the size of the command history\[\r\n\]+Type \"help show history\" followed by show history subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help show history"
# test help show language
*************** gdb_test "help undisplay" "Cancel some e
*** 543,549 ****
# test help unset environment
gdb_test "help unset environment" "Cancel environment variable VAR for the program\.\[\r\n\]+This does not affect the program until the next \"run\" command\." "help unset environment"
# test help unset
! gdb_test "help unset" "Complement to certain \"set\" commands.\[\r\n\]+List of unset subcommands:\[\r\n\]+unset environment -- Cancel environment variable VAR for the program\[\r\n\]+Type \"help unset\" followed by unset subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help unset"
# test help up
gdb_test "help up" "Select and print stack frame that called this one\.\[\r\n\]+An argument says how many frames up to go\." "help up"
# test help up-silently
--- 569,575 ----
# test help unset environment
gdb_test "help unset environment" "Cancel environment variable VAR for the program\.\[\r\n\]+This does not affect the program until the next \"run\" command\." "help unset environment"
# test help unset
! gdb_test "help unset" "Complement to certain \"set\" commands\.\[\r\n\]+List of unset subcommands:\[\r\n\]+unset environment -- Cancel environment variable VAR for the program\[\r\n\]+Type \"help unset\" followed by unset subcommand name for full documentation\.\[\r\n\]+Command name abbreviations are allowed if unambiguous\." "help unset"
# test help up
gdb_test "help up" "Select and print stack frame that called this one\.\[\r\n\]+An argument says how many frames up to go\." "help up"
# test help up-silently
Index: testsuite/gdb.base/default.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/default.exp,v
retrieving revision 1.8
diff -c -3 -p -r1.8 default.exp
*** default.exp 2002/03/23 00:05:29 1.8
--- default.exp 2002/03/29 01:14:33
*************** set timeout 60
*** 34,39 ****
--- 34,47 ----

gdb_test "add-symbol-file" "add-symbol-file takes a file name and an address" "add-symbol-file"

+ # test append
+ gdb_test "append" "\"append\" must be followed by a subcommand\.\[\r\n\]+List of append subcommands:.*"
+ gdb_test "append binary" "\"append binary\" must be followed by a subcommand\.\[\r\n\]+List of append binary subcommands:.*"
+ gdb_test "append memory" "Missing filename\."
+ gdb_test "append value" "Missing filename\."
+ gdb_test "append binary memory" "Missing filename\."
+ gdb_test "append binary value" "Missing filename\."
+
setup_xfail "mips-idt-*"
send_gdb "attach\n"
gdb_expect {
*************** gdb_test "document" "Argument required .
*** 191,196 ****
--- 199,220 ----
gdb_test "down" "No stack.*" "down"
#test down-silently
gdb_test "down-silently" "No stack." "down-silently"
+ # test dump
+ gdb_test "dump" "\"dump\" must be followed by a subcommand\.\[\r\n\]+List of dump subcommands:.*"
+ gdb_test "dump binary" "\"dump binary\" must be followed by a subcommand\.\[\r\n\]+List of dump binary subcommands:.*"
+ gdb_test "dump ihex" "\"dump ihex\" must be followed by a subcommand\.\[\r\n\]+List of dump ihex subcommands:.*"
+ gdb_test "dump memory" "Missing filename\."
+ gdb_test "dump srec" "\"dump srec\" must be followed by a subcommand\.\[\r\n\]+List of dump srec subcommands:.*"
+ gdb_test "dump tekhex" "\"dump tekhex\" must be followed by a subcommand\.\[\r\n\]+List of dump tekhex subcommands:.*"
+ gdb_test "dump value" "Missing filename\."
+ gdb_test "dump binary memory" "Missing filename\."
+ gdb_test "dump binary value" "Missing filename\."
+ gdb_test "dump ihex memory" "Missing filename\."
+ gdb_test "dump ihex value" "Missing filename\."
+ gdb_test "dump srec memory" "Missing filename\."
+ gdb_test "dump srec value" "Missing filename\."
+ gdb_test "dump tekhex memory" "Missing filename\."
+ gdb_test "dump tekhex value" "Missing filename\."
#test echo
gdb_test "echo" "" "echo"
#test enable breakpoints delete
*************** No program loaded.*$gdb_prompt $"\
*** 490,495 ****
--- 514,522 ----

#test rbreak
gdb_test "rbreak" "" "rbreak"
+
+ # test restore
+ gdb_test "restore" "You can't do that without a process to debug\."

#test return
# The middle case accomodated the OBSOLETE a29k, where doing the "ni"

File: cli/cli-dump.c:
===================================================================
/* Dump-to-file commands, for GDB, the GNU debugger.

Copyright 2002 Free Software Foundation, Inc.

Contributed by Red Hat.

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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */

#include "defs.h"
#include "gdb_string.h"
#include "cli/cli-decode.h"
#include "cli/cli-cmds.h"
#include "value.h"
#include "completer.h"
#include "cli/cli-dump.h"
#include "gdb_assert.h"
#include <ctype.h>
#include "target.h"

#define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))

char *
skip_spaces (char *chp)
{
if (chp == NULL)
return NULL;
while (isspace (*chp))
chp++;
return chp;
}

char *
scan_expression_with_cleanup (char **cmd, const char *def)
{
if ((*cmd) == NULL || (**cmd) == '\0')
{
char *exp = xstrdup (def);
make_cleanup (xfree, exp);
return exp;
}
else
{
char *exp;
char *end;

end = (*cmd) + strcspn (*cmd, " \t");
exp = savestring ((*cmd), end - (*cmd));
make_cleanup (xfree, exp);
(*cmd) = skip_spaces (end);
return exp;
}
}

static void
do_fclose_cleanup (void *arg)
{
FILE *file = arg;
fclose (arg);
}

static struct cleanup *
make_cleanup_fclose (FILE *file)
{
return make_cleanup (do_fclose_cleanup, file);
}

char *
scan_filename_with_cleanup (char **cmd, const char *defname)
{
char *filename;
char *fullname;

/* FIXME: Need to get the ``/a(ppend)'' flag from somewhere. */

/* File. */
if ((*cmd) == NULL)
{
if (defname == NULL)
error ("Missing filename.");
filename = xstrdup (defname);
make_cleanup (xfree, filename);
}
else
{
/* FIXME: should parse a possibly quoted string. */
char *end;

(*cmd) = skip_spaces (*cmd);
end = *cmd + strcspn (*cmd, " \t");
filename = savestring ((*cmd), end - (*cmd));
make_cleanup (xfree, filename);
(*cmd) = skip_spaces (end);
}
gdb_assert (filename != NULL);

fullname = tilde_expand (filename);
make_cleanup (xfree, fullname);

return fullname;
}

FILE *
fopen_with_cleanup (char *filename, const char *mode)
{
FILE *file = fopen (filename, mode);
if (file == NULL)
perror_with_name (filename);
make_cleanup_fclose (file);
return file;
}

static bfd *
bfd_openr_with_cleanup (const char *filename, const char *target)
{
bfd *ibfd;

if ((ibfd = bfd_openr (filename, target)) == NULL)
error ("Failed to open %s: %s.", filename,
bfd_errmsg (bfd_get_error ()));

make_cleanup_bfd_close (ibfd);
if (!bfd_check_format (ibfd, bfd_object))
error ("'%s' is not a recognized file format.", filename);

return ibfd;
}

static bfd *
bfd_openw_with_cleanup (char *filename, const char *target, char *mode)
{
bfd *obfd;

if (*mode == 'w') /* Write: create new file */
{
if ((obfd = bfd_openw (filename, target)) == NULL)
error ("Failed to open %s: %s.", filename,
bfd_errmsg (bfd_get_error ()));
make_cleanup_bfd_close (obfd);
if (!bfd_set_format (obfd, bfd_object))
error ("bfd_openw_with_cleanup: %s.", bfd_errmsg (bfd_get_error ()));
}
else if (*mode == 'a') /* Append to existing file */
{ /* FIXME -- doesn't work... */
error ("bfd_openw does not work with append.");
}
else
error ("bfd_openw_with_cleanup: unknown mode %s.", mode);

return obfd;
}

struct cmd_list_element *dump_cmdlist;
struct cmd_list_element *append_cmdlist;
struct cmd_list_element *srec_cmdlist;
struct cmd_list_element *ihex_cmdlist;
struct cmd_list_element *tekhex_cmdlist;
struct cmd_list_element *binary_dump_cmdlist;
struct cmd_list_element *binary_append_cmdlist;

static void
dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump\" must be followed by a subcommand.\n\n");
help_list (dump_cmdlist, "dump ", -1, gdb_stdout);
}

static void
append_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"append\" must be followed by a subcommand.\n\n");
help_list (dump_cmdlist, "append ", -1, gdb_stdout);
}

static void
dump_binary_file (char *filename, char *mode,
char *buf, int len)
{
FILE *file;
int status;

file = fopen_with_cleanup (filename, mode);
status = fwrite (buf, len, 1, file);
if (status != 1)
perror_with_name (filename);
}

static void
dump_bfd_file (char *filename, char *mode,
char *target, CORE_ADDR vaddr,
char *buf, int len)
{
bfd *obfd;
asection *osection;

obfd = bfd_openw_with_cleanup (filename, target, mode);
osection = bfd_make_section_anyway (obfd, ".newsec");
bfd_set_section_size (obfd, osection, len);
bfd_set_section_vma (obfd, osection, vaddr);
bfd_set_section_alignment (obfd, osection, 0);
bfd_set_section_flags (obfd, osection, 0x203);
osection->entsize = 0;
bfd_set_section_contents (obfd, osection, buf, 0, len);
}

static void
dump_memory_to_file (char *cmd, char *mode, char *file_format)
{
struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
CORE_ADDR lo;
CORE_ADDR hi;
ULONGEST count;
char *filename;
void *buf;
char *lo_exp;
char *hi_exp;
int len;

/* Open the file. */
filename = scan_filename_with_cleanup (&cmd, NULL);

/* Find the low address. */
if (cmd == NULL || *cmd == '\0')
error ("Missing start address.");
lo_exp = scan_expression_with_cleanup (&cmd, NULL);

/* Find the second address - rest of line. */
if (cmd == NULL || *cmd == '\0')
error ("Missing stop address.");
hi_exp = cmd;

lo = parse_and_eval_address (lo_exp);
hi = parse_and_eval_address (hi_exp);
if (hi <= lo)
error ("Invalid memory address range (start >= end).");
count = hi - lo;

/* FIXME: Should use read_memory_partial() and a magic blocking
value. */
buf = xmalloc (count);
make_cleanup (xfree, buf);
target_read_memory (lo, buf, count);

/* Have everything. Open/write the data. */
if (file_format == NULL || strcmp (file_format, "binary") == 0)
{
dump_binary_file (filename, mode, buf, count);
}
else
{
dump_bfd_file (filename, mode, file_format, lo, buf, count);
}

do_cleanups (old_cleanups);
}

static void
dump_memory_command (char *cmd, char *mode)
{
dump_memory_to_file (cmd, mode, "binary");
}

static void
dump_value_to_file (char *cmd, char *mode, char *file_format)
{
struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
struct value *val;
char *filename;

/* Open the file. */
filename = scan_filename_with_cleanup (&cmd, NULL);

/* Find the value. */
if (cmd == NULL || *cmd == '\0')
error ("No value to %s.", *mode == 'a' ? "append" : "dump");
val = parse_and_eval (cmd);
if (val == NULL)
error ("Invalid expression.");

/* Have everything. Open/write the data. */
if (file_format == NULL || strcmp (file_format, "binary") == 0)
{
dump_binary_file (filename, mode, VALUE_CONTENTS (val),
TYPE_LENGTH (VALUE_TYPE (val)));
}
else
{
CORE_ADDR vaddr;

if (VALUE_LVAL (val))
{
vaddr = VALUE_ADDRESS (val);
}
else
{
vaddr = 0;
warning ("value is not an lval: address assumed to be zero");
}

dump_bfd_file (filename, mode, file_format, vaddr,
VALUE_CONTENTS (val),
TYPE_LENGTH (VALUE_TYPE (val)));
}

do_cleanups (old_cleanups);
}

static void
dump_value_command (char *cmd, char *mode)
{
dump_value_to_file (cmd, mode, "binary");
}

static void
dump_filetype (char *cmd, char *mode, char *filetype)
{
char *suffix = cmd;

if (cmd == NULL || *cmd == '\0')
error ("Missing subcommand: try 'help %s %s'.",
mode[0] == 'a' ? "append" : "dump",
filetype);

suffix += strcspn (cmd, " \t");

if (suffix != cmd)
{
if (strncmp ("memory", cmd, suffix - cmd) == 0)
{
dump_memory_to_file (suffix, mode, filetype);
return;
}
else if (strncmp ("value", cmd, suffix - cmd) == 0)
{
dump_value_to_file (suffix, mode, filetype);
return;
}
}

error ("dump %s: unknown subcommand '%s' -- try 'value' or 'memory'.",
filetype, cmd);
}

static void
dump_srec_memory (char *args, int from_tty)
{
dump_memory_to_file (args, "w", "srec");
}

static void
dump_srec_value (char *args, int from_tty)
{
dump_value_to_file (args, "w", "srec");
}

static void
dump_ihex_memory (char *args, int from_tty)
{
dump_memory_to_file (args, "w", "ihex");
}

static void
dump_ihex_value (char *args, int from_tty)
{
dump_value_to_file (args, "w", "ihex");
}

static void
dump_tekhex_memory (char *args, int from_tty)
{
dump_memory_to_file (args, "w", "tekhex");
}

static void
dump_tekhex_value (char *args, int from_tty)
{
dump_value_to_file (args, "w", "tekhex");
}

static void
dump_binary_memory (char *args, int from_tty)
{
dump_memory_to_file (args, "w", "binary");
}

static void
dump_binary_value (char *args, int from_tty)
{
dump_value_to_file (args, "w", "binary");
}

static void
append_binary_memory (char *args, int from_tty)
{
dump_memory_to_file (args, "a", "binary");
}

static void
append_binary_value (char *args, int from_tty)
{
dump_value_to_file (args, "a", "binary");
}

struct dump_context
{
void (*func) (char *cmd, char *mode);
char *mode;
};

static void
call_dump_func (struct cmd_list_element *c, char *args, int from_tty)
{
struct dump_context *d = get_cmd_context (c);
d->func (args, d->mode);
}

void
add_dump_command (char *name, void (*func) (char *args, char *mode),
char *descr)

{
struct cmd_list_element *c;
struct dump_context *d;

c = add_cmd (name, all_commands, NULL, descr, &dump_cmdlist);
c->completer = filename_completer;
d = XMALLOC (struct dump_context);
d->func = func;
d->mode = "w";
set_cmd_context (c, d);
c->func = call_dump_func;

c = add_cmd (name, all_commands, NULL, descr, &append_cmdlist);
c->completer = filename_completer;
d = XMALLOC (struct dump_context);
d->func = func;
d->mode = "a";
set_cmd_context (c, d);
c->func = call_dump_func;

/* Replace "Dump " at start of docstring with "Append "
(borrowed from add_show_from_set). */
if ( c->doc[0] == 'W'
&& c->doc[1] == 'r'
&& c->doc[2] == 'i'
&& c->doc[3] == 't'
&& c->doc[4] == 'e'
&& c->doc[5] == ' ')
c->doc = concat ("Append ", c->doc + 6, NULL);
}

/* Opaque data for restore_section_callback. */
struct callback_data {
unsigned long load_offset;
CORE_ADDR load_start;
CORE_ADDR load_end;
};

/* Function: restore_section_callback.

Callback function for bfd_map_over_sections.
Selectively loads the sections into memory. */

static void
restore_section_callback (bfd *ibfd, asection *isec, void *args)
{
struct callback_data *data = args;
bfd_vma sec_start = bfd_section_vma (ibfd, isec);
bfd_size_type size = bfd_section_size (ibfd, isec);
bfd_vma sec_end = sec_start + size;
bfd_size_type sec_offset = 0;
bfd_size_type sec_load_count = size;
struct cleanup *old_chain;
char *buf;
int ret;

/* Ignore non-loadable sections, eg. from elf files. */
if (!(bfd_get_section_flags (ibfd, isec) & SEC_LOAD))
return;

/* Does the section overlap with the desired restore range? */
if (sec_end <= data->load_start
|| (data->load_end > 0 && sec_start >= data->load_end))
{
/* No, no useable data in this section. */
printf_filtered ("skipping section %s...\n",
bfd_section_name (ibfd, isec));
return;
}

/* Compare section address range with user-requested
address range (if any). Compute where the actual
transfer should start and end. */
if (sec_start < data->load_start)
sec_offset = data->load_start - sec_start;
/* Size of a partial transfer: */
sec_load_count -= sec_offset;
if (data->load_end > 0 && sec_end > data->load_end)
sec_load_count -= sec_end - data->load_end;

/* Get the data. */
buf = xmalloc (size);
old_chain = make_cleanup (xfree, buf);
if (!bfd_get_section_contents (ibfd, isec, buf, 0, size))
error ("Failed to read bfd file %s: '%s'.", bfd_get_filename (ibfd),
bfd_errmsg (bfd_get_error ()));

printf_filtered ("Restoring section %s (0x%lx to 0x%lx)",
bfd_section_name (ibfd, isec),
(unsigned long) sec_start,
(unsigned long) sec_end);

if (data->load_offset != 0 || data->load_start != 0 || data->load_end != 0)
printf_filtered (" into memory (0x%lx to 0x%lx)\n",
(unsigned long) sec_start
+ sec_offset + data->load_offset,
(unsigned long) sec_start + sec_offset
+ data->load_offset + sec_load_count);
else
puts_filtered ("\n");

/* Write the data. */
ret = target_write_memory (sec_start + sec_offset + data->load_offset,
buf + sec_offset, sec_load_count);
if (ret != 0)
warning ("restore: memory write failed (%s).", safe_strerror (ret));
do_cleanups (old_chain);
return;
}

static void
restore_binary_file (char *filename, struct callback_data *data)
{
FILE *file = fopen_with_cleanup (filename, "r");
int status;
char *buf;
long len;

/* Get the file size for reading. */
if (fseek (file, 0, SEEK_END) == 0)
len = ftell (file);
else
perror_with_name (filename);

if (len <= data->load_start)
error ("Start address is greater than length of binary file %s.",
filename);

/* Chop off "len" if it exceeds the requested load_end addr. */
if (data->load_end != 0 && data->load_end < len)
len = data->load_end;
/* Chop off "len" if the requested load_start addr skips some bytes. */
if (data->load_start > 0)
len -= data->load_start;

printf_filtered
("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
filename,
(unsigned long) data->load_start + data->load_offset,
(unsigned long) data->load_start + data->load_offset + len);

/* Now set the file pos to the requested load start pos. */
if (fseek (file, data->load_start, SEEK_SET) != 0)
perror_with_name (filename);

/* Now allocate a buffer and read the file contents. */
buf = xmalloc (len);
make_cleanup (xfree, buf);
if (fread (buf, 1, len, file) != len)
perror_with_name (filename);

/* Now write the buffer into target memory. */
len = target_write_memory (data->load_start + data->load_offset, buf, len);
if (len != 0)
warning ("restore: memory write failed (%s).", safe_strerror (len));
return;
}

static void
restore_command (char *args, int from_tty)
{
char *filename;
struct callback_data data;
bfd *ibfd;
int binary_flag = 0;

if (!target_has_execution)
noprocess ();

data.load_offset = 0;
data.load_start = 0;
data.load_end = 0;

/* Parse the input arguments. First is filename (required). */
filename = scan_filename_with_cleanup (&args, NULL);
if (args != NULL && *args != '\0')
{
char *binary_string = "binary";

/* Look for optional "binary" flag. */
if (strncmp (args, binary_string, strlen (binary_string)) == 0)
{
binary_flag = 1;
args += strlen (binary_string);
args = skip_spaces (args);
}
/* Parse offset (optional). */
if (args != NULL && *args != '\0')
data.load_offset =
parse_and_eval_address (scan_expression_with_cleanup (&args,
NULL));
if (args != NULL && *args != '\0')
{
/* Parse start address (optional). */
data.load_start =
parse_and_eval_address (scan_expression_with_cleanup (&args,
NULL));
if (args != NULL && *args != '\0')
{
/* Parse end address (optional). */
data.load_end = parse_and_eval_address (args);
if (data.load_end <= data.load_start)
error ("Start must be less than end.");
}
}
}

if (info_verbose)
printf_filtered ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
filename, (unsigned long) data.load_offset,
(unsigned long) data.load_start,
(unsigned long) data.load_end);

if (binary_flag)
{
restore_binary_file (filename, &data);
}
else
{
/* Open the file for loading. */
ibfd = bfd_openr_with_cleanup (filename, NULL);

/* Process the sections. */
bfd_map_over_sections (ibfd, restore_section_callback, &data);
}
return;
}

static void
srec_dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump srec\" must be followed by a subcommand.\n");
help_list (srec_cmdlist, "dump srec ", -1, gdb_stdout);
}

static void
ihex_dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump ihex\" must be followed by a subcommand.\n");
help_list (ihex_cmdlist, "dump ihex ", -1, gdb_stdout);
}

static void
tekhex_dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump tekhex\" must be followed by a subcommand.\n");
help_list (tekhex_cmdlist, "dump tekhex ", -1, gdb_stdout);
}

static void
binary_dump_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"dump binary\" must be followed by a subcommand.\n");
help_list (binary_dump_cmdlist, "dump binary ", -1, gdb_stdout);
}

static void
binary_append_command (char *cmd, int from_tty)
{
printf_unfiltered ("\"append binary\" must be followed by a subcommand.\n");
help_list (binary_append_cmdlist, "append binary ", -1, gdb_stdout);
}

void
_initialize_cli_dump (void)
{
struct cmd_list_element *c;
add_prefix_cmd ("dump", class_vars, dump_command, "\
Dump target code/data to a local file.",
&dump_cmdlist, "dump ",
0/*allow-unknown*/,
&cmdlist);
add_prefix_cmd ("append", class_vars, append_command, "\
Append target code/data to a local file.",
&append_cmdlist, "append ",
0/*allow-unknown*/,
&cmdlist);

add_dump_command ("memory", dump_memory_command, "\
Write contents of memory to a raw binary file.\n\
Arguments are FILE START STOP. Writes the contents of memory within the\n\
range [START .. STOP) to the specifed FILE in raw target ordered bytes.");

add_dump_command ("value", dump_value_command, "\
Write the value of an expression to a raw binary file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION to\n\
the specified FILE in raw target ordered bytes.");

add_prefix_cmd ("srec", all_commands, srec_dump_command, "\
Write target code/data to an srec file.",
&srec_cmdlist, "dump srec ",
0 /*allow-unknown*/,
&dump_cmdlist);

add_prefix_cmd ("ihex", all_commands, ihex_dump_command, "\
Write target code/data to an intel hex file.",
&ihex_cmdlist, "dump ihex ",
0 /*allow-unknown*/,
&dump_cmdlist);

add_prefix_cmd ("tekhex", all_commands, tekhex_dump_command, "\
Write target code/data to a tekhex file.",
&tekhex_cmdlist, "dump tekhex ",
0 /*allow-unknown*/,
&dump_cmdlist);

add_prefix_cmd ("binary", all_commands, binary_dump_command, "\
Write target code/data to a raw binary file.",
&binary_dump_cmdlist, "dump binary ",
0 /*allow-unknown*/,
&dump_cmdlist);

add_prefix_cmd ("binary", all_commands, binary_append_command, "\
Append target code/data to a raw binary file.",
&binary_append_cmdlist, "append binary ",
0 /*allow-unknown*/,
&append_cmdlist);

add_cmd ("memory", all_commands, dump_srec_memory, "\
Write contents of memory to an srec file.\n\
Arguments are FILE START STOP. Writes the contents of memory\n\
within the range [START .. STOP) to the specifed FILE in srec format.",
&srec_cmdlist);

add_cmd ("value", all_commands, dump_srec_value, "\
Write the value of an expression to an srec file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in srec format.",
&srec_cmdlist);

add_cmd ("memory", all_commands, dump_ihex_memory, "\
Write contents of memory to an ihex file.\n\
Arguments are FILE START STOP. Writes the contents of memory within\n\
the range [START .. STOP) to the specifed FILE in intel hex format.",
&ihex_cmdlist);

add_cmd ("value", all_commands, dump_ihex_value, "\
Write the value of an expression to an ihex file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in intel hex format.",
&ihex_cmdlist);

add_cmd ("memory", all_commands, dump_tekhex_memory, "\
Write contents of memory to a tekhex file.\n\
Arguments are FILE START STOP. Writes the contents of memory\n\
within the range [START .. STOP) to the specifed FILE in tekhex format.",
&tekhex_cmdlist);

add_cmd ("value", all_commands, dump_tekhex_value, "\
Write the value of an expression to a tekhex file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in tekhex format.",
&tekhex_cmdlist);

add_cmd ("memory", all_commands, dump_binary_memory, "\
Write contents of memory to a raw binary file.\n\
Arguments are FILE START STOP. Writes the contents of memory\n\
within the range [START .. STOP) to the specifed FILE in binary format.",
&binary_dump_cmdlist);

add_cmd ("value", all_commands, dump_binary_value, "\
Write the value of an expression to a raw binary file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in raw target ordered bytes.",
&binary_dump_cmdlist);

add_cmd ("memory", all_commands, append_binary_memory, "\
Append contents of memory to a raw binary file.\n\
Arguments are FILE START STOP. Writes the contents of memory within the\n\
range [START .. STOP) to the specifed FILE in raw target ordered bytes.",
&binary_append_cmdlist);

add_cmd ("value", all_commands, append_binary_value, "\
Append the value of an expression to a raw binary file.\n\
Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
to the specified FILE in raw target ordered bytes.",
&binary_append_cmdlist);

c = add_com ("restore", class_vars, restore_command,
"Restore the contents of FILE to target memory.\n\
Arguments are FILE OFFSET START END where all except FILE are optional.\n\
OFFSET will be added to the base address of the file (default zero).\n\
If START and END are given, only the file contents within that range
(file relative) will be restored to target memory.");
c->completer = filename_completer;
/* FIXME: completers for other commands. */
}

File: cli/cli-dump.h:
===================================================================
/* Dump-to-file commands, for GDB, the GNU debugger.

Copyright 2001 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 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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */

#ifndef CLI_DUMP_H
#define CLI_DUMP_H

extern void add_dump_command (char *name,
void (*func) (char *args, char *mode),
char *descr);

/* Utilities for doing the dump. */
extern char *scan_filename_with_cleanup (char **cmd, const char *defname);

extern char *scan_expression_with_cleanup (char **cmd, const char *defname);

extern FILE *fopen_with_cleanup (char *filename, const char *mode);

extern char *skip_spaces (char *inp);

extern struct value *parse_and_eval_with_error (char *exp, const char *fmt, ...) ATTR_FORMAT (printf, 2, 3);

#endif

File: testsuite/gdb.base/dump.c
===================================================================
#define ARRSIZE 32
int intarray[ARRSIZE], intarray2[ARRSIZE];

struct teststruct {
int a;
int b;
int c;
int d;
int e;
int f;
int g;
} intstruct, intstruct2;

void checkpoint1 ()
{
/* intarray and teststruct have been initialized. */
}

void
zero_all ()
{
memset ((char *) &intarray, 0, sizeof (intarray));
memset ((char *) &intarray2, 0, sizeof (intarray2));
memset ((char *) &intstruct, 0, sizeof (intstruct));
memset ((char *) &intstruct2, 0, sizeof (intstruct2));
}

main()
{
int i;

for (i = 0; i < ARRSIZE; i++)
intarray[i] = i+1;

intstruct.a = 12 * 1;
intstruct.b = 12 * 2;
intstruct.c = 12 * 3;
intstruct.d = 12 * 4;
intstruct.e = 12 * 5;
intstruct.f = 12 * 6;
intstruct.g = 12 * 7;

checkpoint1 ();
}

File: testsuite/gdb.base/dump.exp
===================================================================

# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

# Please email any bugs, comments, and/or additions to this file to:
# bug-gdb@prep.ai.mit.edu

# This file was written by Michael Snyder (msnyder@redhat.com)
# This is a test for the gdb command "dump".

if $tracelevel then {
strace $tracelevel
}

set prms_id 0
set bug_id 0

set testfile "dump"

set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}

if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
}

# Start with a fresh gdb.

gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}

# Clean up any stale output files from previous test runs

remote_exec build "rm -f intarr1.bin intarr1b.bin intarr1.ihex intarr1.srec intarr1.tekhex intarr2.bin intarr2b.bin intarr2.ihex intarr2.srec intarr2.tekhex intstr1.bin intstr1b.bin intstr1.ihex intstr1.srec intstr1.tekhex intstr2.bin intstr2b.bin intstr2.ihex intstr2.srec intstr2.tekhex intarr3.srec"

# Test help (FIXME:)

# Run target program until data structs are initialized.

if { ! [ runto checkpoint1 ] } then {
gdb_suppress_entire_file "Program failed to run, so all tests in this file will automatically fail."
}

# Now generate some dump files.

proc make_dump_file { command msg } {
global gdb_prompt

send_gdb "${command}\n"
gdb_expect {
-re ".*\[Ee\]rror.*$gdb_prompt $" { fail $msg }
-re ".*\[Ww\]arning.*$gdb_prompt $" { fail $msg }
-re ".*\[Uu\]ndefined .*$gdb_prompt $" { fail $msg }
-re ".*$gdb_prompt $" { pass $msg }
timeout { fail "$msg (timeout)" }
}
}

make_dump_file "dump val intarr1.bin intarray" \
"dump array as value, default"

make_dump_file "dump val intstr1.bin intstruct" \
"dump struct as value, default"

make_dump_file "dump bin val intarr1b.bin intarray" \
"dump array as value, binary"

make_dump_file "dump bin val intstr1b.bin intstruct" \
"dump struct as value, binary"

make_dump_file "dump srec val intarr1.srec intarray" \
"dump array as value, srec"

make_dump_file "dump srec val intstr1.srec intstruct" \
"dump struct as value, srec"

make_dump_file "dump ihex val intarr1.ihex intarray" \
"dump array as value, intel hex"

make_dump_file "dump ihex val intstr1.ihex intstruct" \
"dump struct as value, intel hex"

make_dump_file "dump tekhex val intarr1.tekhex intarray" \
"dump array as value, tekhex"

make_dump_file "dump tekhex val intstr1.tekhex intstruct" \
"dump struct as value, tekhex"

proc capture_value { expression } {
global gdb_prompt
global expect_out

set output_string ""
send_gdb "print ${expression}\n"
gdb_expect {
-re ".*\[\r\n\]+.\[0123456789\]+ = (\[^\r\n\]+).*$gdb_prompt $" {
set output_string $expect_out(1,string)
}
default {
fail "capture_value failed on $expression."
}
}
return $output_string
}

set array_start [capture_value "/x &intarray\[0\]"]
set array_end [capture_value "/x &intarray\[32\]"]
set struct_start [capture_value "/x &intstruct"]
set struct_end [capture_value "/x &intstruct + 1"]

set array_val [capture_value "intarray"]
set struct_val [capture_value "intstruct"]

make_dump_file "dump mem intarr2.bin $array_start $array_end" \
"dump array as memory, default"

make_dump_file "dump mem intstr2.bin $struct_start $struct_end" \
"dump struct as memory, default"

make_dump_file "dump bin mem intarr2b.bin $array_start $array_end" \
"dump array as memory, binary"

make_dump_file "dump bin mem intstr2b.bin $struct_start $struct_end" \
"dump struct as memory, binary"

make_dump_file "dump srec mem intarr2.srec $array_start $array_end" \
"dump array as memory, srec"

make_dump_file "dump srec mem intstr2.srec $struct_start $struct_end" \
"dump struct as memory, srec"

make_dump_file "dump ihex mem intarr2.ihex $array_start $array_end" \
"dump array as memory, ihex"

make_dump_file "dump ihex mem intstr2.ihex $struct_start $struct_end" \
"dump struct as memory, ihex"

make_dump_file "dump tekhex mem intarr2.tekhex $array_start $array_end" \
"dump array as memory, tekhex"

make_dump_file "dump tekhex mem intstr2.tekhex $struct_start $struct_end" \
"dump struct as memory, tekhex"

# test complex expressions
make_dump_file \
"dump srec mem intarr3.srec &intarray \(char *\) &intarray + sizeof intarray" \
"dump array as mem, srec, expressions"

# Now start a fresh gdb session, and reload the saved value files.

gdb_exit
gdb_start
gdb_file_cmd ${binfile}

# Reload saved values one by one, and compare.

if { ![string compare $array_val [capture_value "intarray"]] } then {
fail "start with intarray un-initialized"
} else {
pass "start with intarray un-initialized"
}

if { ![string compare $struct_val [capture_value "intstruct"]] } then {
fail "start with intstruct un-initialized"
} else {
pass "start with intstruct un-initialized"
}

proc test_reload_saved_value { filename msg oldval newval } {
global gdb_prompt

gdb_file_cmd $filename
if { ![string compare $oldval [capture_value $newval]] } then {
pass $msg
} else {
fail $msg
}
}

proc test_restore_saved_value { restore_args msg oldval newval } {
global gdb_prompt

gdb_test "restore $restore_args" \
"Restoring .*" \
"Restore command, $msg"

if { ![string compare $oldval [capture_value $newval]] } then {
pass "Restored value, $msg"
} else {
fail "Restored value, $msg"
}
}

test_reload_saved_value "intarr1.srec" "reload array as value, srec" \
$array_val "intarray"
test_reload_saved_value "intstr1.srec" "reload struct as value, srec" \
$struct_val "intstruct"
test_reload_saved_value "intarr2.srec" "reload array as memory, srec" \
$array_val "intarray"
test_reload_saved_value "intstr2.srec" "reload struct as memory, srec" \
$struct_val "intstruct"

test_reload_saved_value "intarr1.ihex" "reload array as value, intel hex" \
$array_val "intarray"
test_reload_saved_value "intstr1.ihex" "reload struct as value, intel hex" \
$struct_val "intstruct"
test_reload_saved_value "intarr2.ihex" "reload array as memory, intel hex" \
$array_val "intarray"
test_reload_saved_value "intstr2.ihex" "reload struct as memory, intel hex" \
$struct_val "intstruct"

test_reload_saved_value "intarr1.tekhex" "reload array as value, tekhex" \
$array_val "intarray"
test_reload_saved_value "intstr1.tekhex" "reload struct as value, tekhex" \
$struct_val "intstruct"
test_reload_saved_value "intarr2.tekhex" "reload array as memory, tekhex" \
$array_val "intarray"
test_reload_saved_value "intstr2.tekhex" "reload struct as memory, tekhex" \
$struct_val "intstruct"

# Start a fresh gdb session

gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}

# Run to main.
if { ! [ runto main ] } then {
gdb_suppress_entire_file "Program failed to run, so remaining tests in this file will automatically fail."
}

if { ![string compare $array_val [capture_value "intarray"]] } then {
fail "start with intarray un-initialized, runto main"
} else {
pass "start with intarray un-initialized, runto main"
}

if { ![string compare $struct_val [capture_value "intstruct"]] } then {
fail "start with intstruct un-initialized, runto main"
} else {
pass "start with intstruct un-initialized, runto main"
}

test_restore_saved_value "intarr1.srec" "array as value, srec" \
$array_val "intarray"

test_restore_saved_value "intstr1.srec" "struct as value, srec" \
$struct_val "intstruct"

gdb_test "print zero_all ()" "void" "zero all"

test_restore_saved_value "intarr2.srec" "array as memory, srec" \
$array_val "intarray"

test_restore_saved_value "intstr2.srec" "struct as memory, srec" \
$struct_val "intstruct"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.ihex" "array as value, ihex" \
$array_val "intarray"

test_restore_saved_value "intstr1.ihex" "struct as value, ihex" \
$struct_val "intstruct"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr2.ihex" "array as memory, ihex" \
$array_val "intarray"

test_restore_saved_value "intstr2.ihex" "struct as memory, ihex" \
$struct_val "intstruct"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.tekhex" "array as value, tekhex" \
$array_val "intarray"

test_restore_saved_value "intstr1.tekhex" "struct as value, tekhex" \
$struct_val "intstruct"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr2.tekhex" "array as memory, tekhex" \
$array_val "intarray"

test_restore_saved_value "intstr2.tekhex" "struct as memory, tekhex" \
$struct_val "intstruct"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.bin binary $array_start" \
"array as value, binary" \
$array_val "intarray"

test_restore_saved_value "intstr1.bin binary $struct_start" \
"struct as value, binary" \
$struct_val "intstruct"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr2.bin binary $array_start" \
"array as memory, binary" \
$array_val "intarray"

test_restore_saved_value "intstr2.bin binary $struct_start" \
"struct as memory, binary" \
$struct_val "intstruct"

# test restore with offset.

set array2_start [capture_value "/x &intarray2\[0\]"]
set struct2_start [capture_value "/x &intstruct2"]
set array2_offset \
[capture_value "/x (char *) &intarray2 - (char *) &intarray"]
set struct2_offset \
[capture_value "/x (char *) &intstruct2 - (char *) &intstruct"]

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.srec $array2_offset" \
"array copy, srec" \
$array_val "intarray2"

test_restore_saved_value "intstr1.srec $struct2_offset" \
"struct copy, srec" \
$struct_val "intstruct2"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.ihex $array2_offset" \
"array copy, ihex" \
$array_val "intarray2"

test_restore_saved_value "intstr1.ihex $struct2_offset" \
"struct copy, ihex" \
$struct_val "intstruct2"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.tekhex $array2_offset" \
"array copy, tekhex" \
$array_val "intarray2"

test_restore_saved_value "intstr1.tekhex $struct2_offset" \
"struct copy, tekhex" \
$struct_val "intstruct2"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.bin binary $array2_start" \
"array copy, binary" \
$array_val "intarray2"

test_restore_saved_value "intstr1.bin binary $struct2_start" \
"struct copy, binary" \
$struct_val "intstruct2"

#
# test restore with start/stop addresses.
#
# For this purpose, we will restore just the third element of the array,
# and check to see that adjacent elements are not modified.
#
# We will need the address and offset of the third and fourth elements.
#

set element3_start [capture_value "/x &intarray\[3\]"]
set element4_start [capture_value "/x &intarray\[4\]"]
set element3_offset \
[capture_value "/x (char *) &intarray\[3\] - (char *) &intarray\[0\]"]
set element4_offset \
[capture_value "/x (char *) &intarray\[4\] - (char *) &intarray\[0\]"]

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.srec 0 $element3_start $element4_start" \
"array partial, srec" \
[capture_value "4"] "intarray\[3\]"

gdb_test "print intarray\[2\] == 0" " = 1" "element 2 not changed - 1"
gdb_test "print intarray\[4\] == 0" " = 1" "element 4 not changed - 1"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.ihex 0 $element3_start $element4_start" \
"array partial, ihex" \
[capture_value "4"] "intarray\[3\]"

gdb_test "print intarray\[2\] == 0" " = 1" "element 2 not changed - 2"
gdb_test "print intarray\[4\] == 0" " = 1" "element 4 not changed - 2"

gdb_test "print zero_all ()" ""

test_restore_saved_value "intarr1.tekhex 0 $element3_start $element4_start" \
"array partial, tekhex" \
[capture_value "4"] "intarray\[3\]"

gdb_test "print intarray\[2\] == 0" " = 1" "element 2 not changed - 3"
gdb_test "print intarray\[4\] == 0" " = 1" "element 4 not changed - 3"

gdb_test "print zero_all ()" ""

test_restore_saved_value \
"intarr1.bin binary $array_start $element3_offset $element4_offset" \
"array partial, binary" \
[capture_value "4"] "intarray\[3\]"

gdb_test "print intarray\[2\] == 0" " = 1" "element 2 not changed - 4"
gdb_test "print intarray\[4\] == 0" " = 1" "element 4 not changed - 4"

gdb_test "print zero_all ()" "" ""

# restore with expressions
test_restore_saved_value \
"intarr3.srec ${array2_start}-${array_start} &intarray\[3\] &intarray\[4\]" \
"array partial with expressions" \
[capture_value "4"] "intarray2\[3\]"

gdb_test "print intarray2\[2\] == 0" " = 1" "element 2 not changed, == 4"
gdb_test "print intarray2\[4\] == 0" " = 1" "element 4 not changed, == 4"

# clean up files

remote_exec build "rm -f intarr1.bin intarr1b.bin intarr1.ihex intarr1.srec intarr1.tekhex intarr2.bin intarr2b.bin intarr2.ihex intarr2.srec intarr2.tekhex intstr1.bin intstr1b.bin intstr1.ihex intstr1.srec intstr1.tekhex intstr2.bin intstr2b.bin intstr2.ihex intstr2.srec intstr2.tekhex intarr3.srec"