Home | History | Annotate | Line # | Download | only in cli
      1 /* Dump-to-file commands, for GDB, the GNU debugger.
      2 
      3    Copyright (C) 2002-2024 Free Software Foundation, Inc.
      4 
      5    Contributed by Red Hat.
      6 
      7    This file is part of GDB.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 3 of the License, or
     12    (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21 
     22 #include "cli/cli-decode.h"
     23 #include "cli/cli-cmds.h"
     24 #include "value.h"
     25 #include "completer.h"
     26 #include <ctype.h>
     27 #include "target.h"
     28 #include "readline/tilde.h"
     29 #include "gdbcore.h"
     30 #include "cli/cli-utils.h"
     31 #include "gdb_bfd.h"
     32 #include "gdbsupport/filestuff.h"
     33 #include "gdbsupport/byte-vector.h"
     34 #include "gdbarch.h"
     35 #include "inferior.h"
     36 
     37 static gdb::unique_xmalloc_ptr<char>
     38 scan_expression (const char **cmd, const char *def)
     39 {
     40   if ((*cmd) == NULL || (**cmd) == '\0')
     41     return make_unique_xstrdup (def);
     42   else
     43     {
     44       char *exp;
     45       const char *end;
     46 
     47       end = (*cmd) + strcspn (*cmd, " \t");
     48       exp = savestring ((*cmd), end - (*cmd));
     49       (*cmd) = skip_spaces (end);
     50       return gdb::unique_xmalloc_ptr<char> (exp);
     51     }
     52 }
     53 
     54 
     55 static gdb::unique_xmalloc_ptr<char>
     56 scan_filename (const char **cmd, const char *defname)
     57 {
     58   gdb::unique_xmalloc_ptr<char> filename;
     59 
     60   /* FIXME: Need to get the ``/a(ppend)'' flag from somewhere.  */
     61 
     62   /* File.  */
     63   if ((*cmd) == NULL)
     64     {
     65       if (defname == NULL)
     66 	error (_("Missing filename."));
     67       filename.reset (xstrdup (defname));
     68     }
     69   else
     70     {
     71       /* FIXME: should parse a possibly quoted string.  */
     72       const char *end;
     73 
     74       (*cmd) = skip_spaces (*cmd);
     75       end = *cmd + strcspn (*cmd, " \t");
     76       filename.reset (savestring ((*cmd), end - (*cmd)));
     77       (*cmd) = skip_spaces (end);
     78     }
     79   gdb_assert (filename != NULL);
     80 
     81   return gdb::unique_xmalloc_ptr<char> (tilde_expand (filename.get ()));
     82 }
     83 
     84 static gdb_bfd_ref_ptr
     85 bfd_openr_or_error (const char *filename, const char *target)
     86 {
     87   gdb_bfd_ref_ptr ibfd (gdb_bfd_openr (filename, target));
     88   if (ibfd == NULL)
     89     error (_("Failed to open %s: %s."), filename,
     90 	   bfd_errmsg (bfd_get_error ()));
     91 
     92   if (!bfd_check_format (ibfd.get (), bfd_object))
     93     error (_("'%s' is not a recognized file format."), filename);
     94 
     95   return ibfd;
     96 }
     97 
     98 static gdb_bfd_ref_ptr
     99 bfd_openw_or_error (const char *filename, const char *target, const char *mode)
    100 {
    101   gdb_bfd_ref_ptr obfd;
    102 
    103   if (*mode == 'w')	/* Write: create new file */
    104     {
    105       obfd = gdb_bfd_openw (filename, target);
    106       if (obfd == NULL)
    107 	error (_("Failed to open %s: %s."), filename,
    108 	       bfd_errmsg (bfd_get_error ()));
    109       if (!bfd_set_format (obfd.get (), bfd_object))
    110 	error (_("bfd_openw_or_error: %s."), bfd_errmsg (bfd_get_error ()));
    111     }
    112   else if (*mode == 'a')	/* Append to existing file.  */
    113     {	/* FIXME -- doesn't work...  */
    114       error (_("bfd_openw does not work with append."));
    115     }
    116   else
    117     error (_("bfd_openw_or_error: unknown mode %s."), mode);
    118 
    119   return obfd;
    120 }
    121 
    122 static struct cmd_list_element *dump_cmdlist;
    123 static struct cmd_list_element *append_cmdlist;
    124 static struct cmd_list_element *srec_cmdlist;
    125 static struct cmd_list_element *ihex_cmdlist;
    126 static struct cmd_list_element *verilog_cmdlist;
    127 static struct cmd_list_element *tekhex_cmdlist;
    128 static struct cmd_list_element *binary_dump_cmdlist;
    129 static struct cmd_list_element *binary_append_cmdlist;
    130 
    131 static void
    132 dump_binary_file (const char *filename, const char *mode,
    133 		  const bfd_byte *buf, ULONGEST len)
    134 {
    135   int status;
    136 
    137   gdb_file_up file = gdb_fopen_cloexec (filename, mode);
    138   if (file == nullptr)
    139     perror_with_name (filename);
    140 
    141   status = fwrite (buf, len, 1, file.get ());
    142   if (status != 1)
    143     perror_with_name (filename);
    144 }
    145 
    146 static void
    147 dump_bfd_file (const char *filename, const char *mode,
    148 	       const char *target, CORE_ADDR vaddr,
    149 	       const bfd_byte *buf, ULONGEST len)
    150 {
    151   asection *osection;
    152 
    153   gdb_bfd_ref_ptr obfd (bfd_openw_or_error (filename, target, mode));
    154   osection = bfd_make_section_anyway (obfd.get (), ".newsec");
    155   bfd_set_section_size (osection, len);
    156   bfd_set_section_vma (osection, vaddr);
    157   bfd_set_section_alignment (osection, 0);
    158   bfd_set_section_flags (osection, (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD));
    159   osection->entsize = 0;
    160   if (!bfd_set_section_contents (obfd.get (), osection, buf, 0, len))
    161     warning (_("writing dump file '%s' (%s)"), filename,
    162 	     bfd_errmsg (bfd_get_error ()));
    163 }
    164 
    165 static void
    166 dump_memory_to_file (const char *cmd, const char *mode, const char *file_format)
    167 {
    168   CORE_ADDR lo;
    169   CORE_ADDR hi;
    170   ULONGEST count;
    171   const char *hi_exp;
    172 
    173   /* Open the file.  */
    174   gdb::unique_xmalloc_ptr<char> filename = scan_filename (&cmd, NULL);
    175 
    176   /* Find the low address.  */
    177   if (cmd == NULL || *cmd == '\0')
    178     error (_("Missing start address."));
    179   gdb::unique_xmalloc_ptr<char> lo_exp = scan_expression (&cmd, NULL);
    180 
    181   /* Find the second address - rest of line.  */
    182   if (cmd == NULL || *cmd == '\0')
    183     error (_("Missing stop address."));
    184   hi_exp = cmd;
    185 
    186   lo = parse_and_eval_address (lo_exp.get ());
    187   hi = parse_and_eval_address (hi_exp);
    188   if (hi <= lo)
    189     error (_("Invalid memory address range (start >= end)."));
    190   count = hi - lo;
    191 
    192   /* FIXME: Should use read_memory_partial() and a magic blocking
    193      value.  */
    194   gdb::byte_vector buf (count);
    195   read_memory (lo, buf.data (), count);
    196 
    197   /* Have everything.  Open/write the data.  */
    198   if (file_format == NULL || strcmp (file_format, "binary") == 0)
    199     dump_binary_file (filename.get (), mode, buf.data (), count);
    200   else
    201     dump_bfd_file (filename.get (), mode, file_format, lo, buf.data (), count);
    202 }
    203 
    204 static void
    205 dump_memory_command (const char *cmd, const char *mode)
    206 {
    207   dump_memory_to_file (cmd, mode, "binary");
    208 }
    209 
    210 static void
    211 dump_value_to_file (const char *cmd, const char *mode, const char *file_format)
    212 {
    213   struct value *val;
    214 
    215   /* Open the file.  */
    216   gdb::unique_xmalloc_ptr<char> filename = scan_filename (&cmd, NULL);
    217 
    218   /* Find the value.  */
    219   if (cmd == NULL || *cmd == '\0')
    220     error (_("No value to %s."), *mode == 'a' ? "append" : "dump");
    221   val = parse_and_eval (cmd);
    222   if (val == NULL)
    223     error (_("Invalid expression."));
    224 
    225   /* Have everything.  Open/write the data.  */
    226   if (file_format == NULL || strcmp (file_format, "binary") == 0)
    227     dump_binary_file (filename.get (), mode, val->contents ().data (),
    228 		      val->type ()->length ());
    229   else
    230     {
    231       CORE_ADDR vaddr;
    232 
    233       if (val->lval ())
    234 	{
    235 	  vaddr = val->address ();
    236 	}
    237       else
    238 	{
    239 	  vaddr = 0;
    240 	  warning (_("value is not an lval: address assumed to be zero"));
    241 	}
    242 
    243       dump_bfd_file (filename.get (), mode, file_format, vaddr,
    244 		     val->contents ().data (),
    245 		     val->type ()->length ());
    246     }
    247 }
    248 
    249 static void
    250 dump_value_command (const char *cmd, const char *mode)
    251 {
    252   dump_value_to_file (cmd, mode, "binary");
    253 }
    254 
    255 static void
    256 dump_srec_memory (const char *args, int from_tty)
    257 {
    258   dump_memory_to_file (args, FOPEN_WB, "srec");
    259 }
    260 
    261 static void
    262 dump_srec_value (const char *args, int from_tty)
    263 {
    264   dump_value_to_file (args, FOPEN_WB, "srec");
    265 }
    266 
    267 static void
    268 dump_ihex_memory (const char *args, int from_tty)
    269 {
    270   dump_memory_to_file (args, FOPEN_WB, "ihex");
    271 }
    272 
    273 static void
    274 dump_ihex_value (const char *args, int from_tty)
    275 {
    276   dump_value_to_file (args, FOPEN_WB, "ihex");
    277 }
    278 
    279 static void
    280 dump_verilog_memory (const char *args, int from_tty)
    281 {
    282   dump_memory_to_file (args, FOPEN_WB, "verilog");
    283 }
    284 
    285 static void
    286 dump_verilog_value (const char *args, int from_tty)
    287 {
    288   dump_value_to_file (args, FOPEN_WB, "verilog");
    289 }
    290 
    291 static void
    292 dump_tekhex_memory (const char *args, int from_tty)
    293 {
    294   dump_memory_to_file (args, FOPEN_WB, "tekhex");
    295 }
    296 
    297 static void
    298 dump_tekhex_value (const char *args, int from_tty)
    299 {
    300   dump_value_to_file (args, FOPEN_WB, "tekhex");
    301 }
    302 
    303 static void
    304 dump_binary_memory (const char *args, int from_tty)
    305 {
    306   dump_memory_to_file (args, FOPEN_WB, "binary");
    307 }
    308 
    309 static void
    310 dump_binary_value (const char *args, int from_tty)
    311 {
    312   dump_value_to_file (args, FOPEN_WB, "binary");
    313 }
    314 
    315 static void
    316 append_binary_memory (const char *args, int from_tty)
    317 {
    318   dump_memory_to_file (args, FOPEN_AB, "binary");
    319 }
    320 
    321 static void
    322 append_binary_value (const char *args, int from_tty)
    323 {
    324   dump_value_to_file (args, FOPEN_AB, "binary");
    325 }
    326 
    327 struct dump_context
    328 {
    329   void (*func) (const char *cmd, const char *mode);
    330   const char *mode;
    331 };
    332 
    333 static void
    334 call_dump_func (const char *args, int from_tty, cmd_list_element *c)
    335 {
    336   struct dump_context *d = (struct dump_context *) c->context ();
    337 
    338   d->func (args, d->mode);
    339 }
    340 
    341 static void
    342 add_dump_command (const char *name,
    343 		  void (*func) (const char *args, const char *mode),
    344 		  const char *descr)
    345 
    346 {
    347   struct cmd_list_element *c;
    348   struct dump_context *d;
    349 
    350   c = add_cmd (name, all_commands, descr, &dump_cmdlist);
    351   c->completer =  filename_completer;
    352   d = XNEW (struct dump_context);
    353   d->func = func;
    354   d->mode = FOPEN_WB;
    355   c->set_context (d);
    356   c->func = call_dump_func;
    357 
    358   c = add_cmd (name, all_commands, descr, &append_cmdlist);
    359   c->completer =  filename_completer;
    360   d = XNEW (struct dump_context);
    361   d->func = func;
    362   d->mode = FOPEN_AB;
    363   c->set_context (d);
    364   c->func = call_dump_func;
    365 
    366   /* Replace "Dump " at start of docstring with "Append " (borrowed
    367      from [deleted] deprecated_add_show_from_set).  */
    368   if (   c->doc[0] == 'W'
    369       && c->doc[1] == 'r'
    370       && c->doc[2] == 'i'
    371       && c->doc[3] == 't'
    372       && c->doc[4] == 'e'
    373       && c->doc[5] == ' ')
    374     c->doc = concat ("Append ", c->doc + 6, (char *)NULL);
    375 }
    376 
    377 /* Selectively loads the sections into memory.  */
    378 
    379 static void
    380 restore_one_section (bfd *ibfd, asection *isec,
    381 		     CORE_ADDR load_offset,
    382 		     CORE_ADDR load_start,
    383 		     CORE_ADDR load_end)
    384 {
    385   bfd_vma sec_start  = bfd_section_vma (isec);
    386   bfd_size_type size = bfd_section_size (isec);
    387   bfd_vma sec_end    = sec_start + size;
    388   bfd_size_type sec_offset = 0;
    389   bfd_size_type sec_load_count = size;
    390   int ret;
    391 
    392   /* Ignore non-loadable sections, eg. from elf files.  */
    393   if (!(bfd_section_flags (isec) & SEC_LOAD))
    394     return;
    395 
    396   /* Does the section overlap with the desired restore range? */
    397   if (sec_end <= load_start
    398       || (load_end > 0 && sec_start >= load_end))
    399     {
    400       /* No, no useable data in this section.  */
    401       gdb_printf (_("skipping section %s...\n"),
    402 		  bfd_section_name (isec));
    403       return;
    404     }
    405 
    406   /* Compare section address range with user-requested
    407      address range (if any).  Compute where the actual
    408      transfer should start and end.  */
    409   if (sec_start < load_start)
    410     sec_offset = load_start - sec_start;
    411   /* Size of a partial transfer.  */
    412   sec_load_count -= sec_offset;
    413   if (load_end > 0 && sec_end > load_end)
    414     sec_load_count -= sec_end - load_end;
    415 
    416   /* Get the data.  */
    417   gdb::byte_vector buf (size);
    418   if (!bfd_get_section_contents (ibfd, isec, buf.data (), 0, size))
    419     error (_("Failed to read bfd file %s: '%s'."), bfd_get_filename (ibfd),
    420 	   bfd_errmsg (bfd_get_error ()));
    421 
    422   gdb_printf ("Restoring section %s (0x%lx to 0x%lx)",
    423 	      bfd_section_name (isec),
    424 	      (unsigned long) sec_start,
    425 	      (unsigned long) sec_end);
    426 
    427   if (load_offset != 0 || load_start != 0 || load_end != 0)
    428     gdb_printf (" into memory (%s to %s)\n",
    429 		paddress (current_inferior ()->arch (),
    430 			  (unsigned long) sec_start
    431 			  + sec_offset + load_offset),
    432 		paddress (current_inferior ()->arch (),
    433 			  (unsigned long) sec_start + sec_offset
    434 			  + load_offset + sec_load_count));
    435   else
    436     gdb_puts ("\n");
    437 
    438   /* Write the data.  */
    439   ret = target_write_memory (sec_start + sec_offset + load_offset,
    440 			     &buf[sec_offset], sec_load_count);
    441   if (ret != 0)
    442     warning (_("restore: memory write failed (%s)."), safe_strerror (ret));
    443 }
    444 
    445 static void
    446 restore_binary_file (const char *filename, CORE_ADDR load_offset,
    447 		     CORE_ADDR load_start, CORE_ADDR load_end)
    448 
    449 {
    450   gdb_file_up file = gdb_fopen_cloexec (filename, FOPEN_RB);
    451   long len;
    452 
    453   if (file == NULL)
    454     error (_("Failed to open %s: %s"), filename, safe_strerror (errno));
    455 
    456   /* Get the file size for reading.  */
    457   if (fseek (file.get (), 0, SEEK_END) == 0)
    458     {
    459       len = ftell (file.get ());
    460       if (len < 0)
    461 	perror_with_name (filename);
    462     }
    463   else
    464     perror_with_name (filename);
    465 
    466   if (len <= load_start)
    467     error (_("Start address is greater than length of binary file %s."),
    468 	   filename);
    469 
    470   /* Chop off "len" if it exceeds the requested load_end addr.  */
    471   if (load_end != 0 && load_end < len)
    472     len = load_end;
    473   /* Chop off "len" if the requested load_start addr skips some bytes.  */
    474   if (load_start > 0)
    475     len -= load_start;
    476 
    477   gdb_printf
    478     ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
    479      filename,
    480      (unsigned long) (load_start + load_offset),
    481      (unsigned long) (load_start + load_offset + len));
    482 
    483   /* Now set the file pos to the requested load start pos.  */
    484   if (fseek (file.get (), load_start, SEEK_SET) != 0)
    485     perror_with_name (filename);
    486 
    487   /* Now allocate a buffer and read the file contents.  */
    488   gdb::byte_vector buf (len);
    489   if (fread (buf.data (), 1, len, file.get ()) != len)
    490     perror_with_name (filename);
    491 
    492   /* Now write the buffer into target memory.  */
    493   len = target_write_memory (load_start + load_offset, buf.data (), len);
    494   if (len != 0)
    495     warning (_("restore: memory write failed (%s)."), safe_strerror (len));
    496 }
    497 
    498 static void
    499 restore_command (const char *args, int from_tty)
    500 {
    501   int binary_flag = 0;
    502 
    503   if (!target_has_execution ())
    504     noprocess ();
    505 
    506   CORE_ADDR load_offset = 0;
    507   CORE_ADDR load_start  = 0;
    508   CORE_ADDR load_end    = 0;
    509 
    510   /* Parse the input arguments.  First is filename (required).  */
    511   gdb::unique_xmalloc_ptr<char> filename = scan_filename (&args, NULL);
    512   if (args != NULL && *args != '\0')
    513     {
    514       static const char binary_string[] = "binary";
    515 
    516       /* Look for optional "binary" flag.  */
    517       if (startswith (args, binary_string))
    518 	{
    519 	  binary_flag = 1;
    520 	  args += strlen (binary_string);
    521 	  args = skip_spaces (args);
    522 	}
    523       /* Parse offset (optional).  */
    524       if (args != NULL && *args != '\0')
    525 	load_offset
    526 	  = (binary_flag
    527 	     ? parse_and_eval_address (scan_expression (&args, NULL).get ())
    528 	     : parse_and_eval_long (scan_expression (&args, NULL).get ()));
    529       if (args != NULL && *args != '\0')
    530 	{
    531 	  /* Parse start address (optional).  */
    532 	  load_start =
    533 	    parse_and_eval_long (scan_expression (&args, NULL).get ());
    534 	  if (args != NULL && *args != '\0')
    535 	    {
    536 	      /* Parse end address (optional).  */
    537 	      load_end = parse_and_eval_long (args);
    538 	      if (load_end <= load_start)
    539 		error (_("Start must be less than end."));
    540 	    }
    541 	}
    542     }
    543 
    544   if (info_verbose)
    545     gdb_printf ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
    546 		filename.get (), (unsigned long) load_offset,
    547 		(unsigned long) load_start,
    548 		(unsigned long) load_end);
    549 
    550   if (binary_flag)
    551     {
    552       restore_binary_file (filename.get (), load_offset, load_start,
    553 			   load_end);
    554     }
    555   else
    556     {
    557       /* Open the file for loading.  */
    558       gdb_bfd_ref_ptr ibfd (bfd_openr_or_error (filename.get (), NULL));
    559 
    560       /* Process the sections.  */
    561       for (asection *sect : gdb_bfd_sections (ibfd))
    562 	restore_one_section (ibfd.get (), sect, load_offset, load_start,
    563 			     load_end);
    564     }
    565 }
    566 
    567 void _initialize_cli_dump ();
    568 void
    569 _initialize_cli_dump ()
    570 {
    571   struct cmd_list_element *c;
    572 
    573   add_basic_prefix_cmd ("dump", class_vars,
    574 			_("Dump target code/data to a local file."),
    575 			&dump_cmdlist,
    576 			0/*allow-unknown*/,
    577 			&cmdlist);
    578   add_basic_prefix_cmd ("append", class_vars,
    579 			_("Append target code/data to a local file."),
    580 			&append_cmdlist,
    581 			0/*allow-unknown*/,
    582 			&cmdlist);
    583 
    584   add_dump_command ("memory", dump_memory_command, "\
    585 Write contents of memory to a raw binary file.\n\
    586 Arguments are FILE START STOP.  Writes the contents of memory within the\n\
    587 range [START .. STOP) to the specified FILE in raw target ordered bytes.");
    588 
    589   add_dump_command ("value", dump_value_command, "\
    590 Write the value of an expression to a raw binary file.\n\
    591 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION to\n\
    592 the specified FILE in raw target ordered bytes.");
    593 
    594   add_basic_prefix_cmd ("srec", all_commands,
    595 			_("Write target code/data to an srec file."),
    596 			&srec_cmdlist,
    597 			0 /*allow-unknown*/,
    598 			&dump_cmdlist);
    599 
    600   add_basic_prefix_cmd ("ihex", all_commands,
    601 			_("Write target code/data to an intel hex file."),
    602 			&ihex_cmdlist,
    603 			0 /*allow-unknown*/,
    604 			&dump_cmdlist);
    605 
    606   add_basic_prefix_cmd ("verilog", all_commands,
    607 			_("Write target code/data to a verilog hex file."),
    608 			&verilog_cmdlist,
    609 			0 /*allow-unknown*/,
    610 			&dump_cmdlist);
    611 
    612   add_basic_prefix_cmd ("tekhex", all_commands,
    613 			_("Write target code/data to a tekhex file."),
    614 			&tekhex_cmdlist,
    615 			0 /*allow-unknown*/,
    616 			&dump_cmdlist);
    617 
    618   add_basic_prefix_cmd ("binary", all_commands,
    619 			_("Write target code/data to a raw binary file."),
    620 			&binary_dump_cmdlist,
    621 			0 /*allow-unknown*/,
    622 			&dump_cmdlist);
    623 
    624   add_basic_prefix_cmd ("binary", all_commands,
    625 			_("Append target code/data to a raw binary file."),
    626 			&binary_append_cmdlist,
    627 			0 /*allow-unknown*/,
    628 			&append_cmdlist);
    629 
    630   add_cmd ("memory", all_commands, dump_srec_memory, _("\
    631 Write contents of memory to an srec file.\n\
    632 Arguments are FILE START STOP.  Writes the contents of memory\n\
    633 within the range [START .. STOP) to the specified FILE in srec format."),
    634 	   &srec_cmdlist);
    635 
    636   add_cmd ("value", all_commands, dump_srec_value, _("\
    637 Write the value of an expression to an srec file.\n\
    638 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
    639 to the specified FILE in srec format."),
    640 	   &srec_cmdlist);
    641 
    642   add_cmd ("memory", all_commands, dump_ihex_memory, _("\
    643 Write contents of memory to an ihex file.\n\
    644 Arguments are FILE START STOP.  Writes the contents of memory within\n\
    645 the range [START .. STOP) to the specified FILE in intel hex format."),
    646 	   &ihex_cmdlist);
    647 
    648   add_cmd ("value", all_commands, dump_ihex_value, _("\
    649 Write the value of an expression to an ihex file.\n\
    650 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
    651 to the specified FILE in intel hex format."),
    652 	   &ihex_cmdlist);
    653 
    654   add_cmd ("memory", all_commands, dump_verilog_memory, _("\
    655 Write contents of memory to a verilog hex file.\n\
    656 Arguments are FILE START STOP.  Writes the contents of memory within\n\
    657 the range [START .. STOP) to the specified FILE in verilog hex format."),
    658 	   &verilog_cmdlist);
    659 
    660   add_cmd ("value", all_commands, dump_verilog_value, _("\
    661 Write the value of an expression to a verilog hex file.\n\
    662 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
    663 to the specified FILE in verilog hex format."),
    664 	   &verilog_cmdlist);
    665 
    666   add_cmd ("memory", all_commands, dump_tekhex_memory, _("\
    667 Write contents of memory to a tekhex file.\n\
    668 Arguments are FILE START STOP.  Writes the contents of memory\n\
    669 within the range [START .. STOP) to the specified FILE in tekhex format."),
    670 	   &tekhex_cmdlist);
    671 
    672   add_cmd ("value", all_commands, dump_tekhex_value, _("\
    673 Write the value of an expression to a tekhex file.\n\
    674 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
    675 to the specified FILE in tekhex format."),
    676 	   &tekhex_cmdlist);
    677 
    678   add_cmd ("memory", all_commands, dump_binary_memory, _("\
    679 Write contents of memory to a raw binary file.\n\
    680 Arguments are FILE START STOP.  Writes the contents of memory\n\
    681 within the range [START .. STOP) to the specified FILE in binary format."),
    682 	   &binary_dump_cmdlist);
    683 
    684   add_cmd ("value", all_commands, dump_binary_value, _("\
    685 Write the value of an expression to a raw binary file.\n\
    686 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
    687 to the specified FILE in raw target ordered bytes."),
    688 	   &binary_dump_cmdlist);
    689 
    690   add_cmd ("memory", all_commands, append_binary_memory, _("\
    691 Append contents of memory to a raw binary file.\n\
    692 Arguments are FILE START STOP.  Writes the contents of memory within the\n\
    693 range [START .. STOP) to the specified FILE in raw target ordered bytes."),
    694 	   &binary_append_cmdlist);
    695 
    696   add_cmd ("value", all_commands, append_binary_value, _("\
    697 Append the value of an expression to a raw binary file.\n\
    698 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
    699 to the specified FILE in raw target ordered bytes."),
    700 	   &binary_append_cmdlist);
    701 
    702   c = add_com ("restore", class_vars, restore_command, _("\
    703 Restore the contents of FILE to target memory.\n\
    704 Arguments are FILE OFFSET START END where all except FILE are optional.\n\
    705 OFFSET will be added to the base address of the file (default zero).\n\
    706 If START and END are given, only the file contents within that range\n\
    707 (file relative) will be restored to target memory."));
    708   c->completer = filename_completer;
    709   /* FIXME: completers for other commands.  */
    710 }
    711