1 /* Dump-to-file commands, for GDB, the GNU debugger.
2 
3    Copyright (C) 2002-2021 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 "defs.h"
23 #include "cli/cli-decode.h"
24 #include "cli/cli-cmds.h"
25 #include "value.h"
26 #include "completer.h"
27 #include <ctype.h>
28 #include "target.h"
29 #include "readline/tilde.h"
30 #include "gdbcore.h"
31 #include "cli/cli-utils.h"
32 #include "gdb_bfd.h"
33 #include "gdbsupport/filestuff.h"
34 #include "gdbsupport/byte-vector.h"
35 #include "gdbarch.h"
36 
37 static gdb::unique_xmalloc_ptr<char>
scan_expression(const char ** cmd,const char * def)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>
scan_filename(const char ** cmd,const char * defname)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
bfd_openr_or_error(const char * filename,const char * target)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
bfd_openw_or_error(const char * filename,const char * target,const char * mode)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
dump_binary_file(const char * filename,const char * mode,const bfd_byte * buf,ULONGEST len)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
dump_bfd_file(const char * filename,const char * mode,const char * target,CORE_ADDR vaddr,const bfd_byte * buf,ULONGEST len)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
dump_memory_to_file(const char * cmd,const char * mode,const char * file_format)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
dump_memory_command(const char * cmd,const char * mode)205 dump_memory_command (const char *cmd, const char *mode)
206 {
207   dump_memory_to_file (cmd, mode, "binary");
208 }
209 
210 static void
dump_value_to_file(const char * cmd,const char * mode,const char * file_format)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, value_contents (val),
228 		      TYPE_LENGTH (value_type (val)));
229   else
230     {
231       CORE_ADDR vaddr;
232 
233       if (VALUE_LVAL (val))
234 	{
235 	  vaddr = value_address (val);
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 		     value_contents (val),
245 		     TYPE_LENGTH (value_type (val)));
246     }
247 }
248 
249 static void
dump_value_command(const char * cmd,const char * mode)250 dump_value_command (const char *cmd, const char *mode)
251 {
252   dump_value_to_file (cmd, mode, "binary");
253 }
254 
255 static void
dump_srec_memory(const char * args,int from_tty)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
dump_srec_value(const char * args,int from_tty)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
dump_ihex_memory(const char * args,int from_tty)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
dump_ihex_value(const char * args,int from_tty)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
dump_verilog_memory(const char * args,int from_tty)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
dump_verilog_value(const char * args,int from_tty)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
dump_tekhex_memory(const char * args,int from_tty)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
dump_tekhex_value(const char * args,int from_tty)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
dump_binary_memory(const char * args,int from_tty)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
dump_binary_value(const char * args,int from_tty)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
append_binary_memory(const char * args,int from_tty)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
append_binary_value(const char * args,int from_tty)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
call_dump_func(struct cmd_list_element * c,const char * args,int from_tty)334 call_dump_func (struct cmd_list_element *c, const char *args, int from_tty)
335 {
336   struct dump_context *d = (struct dump_context *) c->context ();
337 
338   d->func (args, d->mode);
339 }
340 
341 static void
add_dump_command(const char * name,void (* func)(const char * args,const char * mode),const char * descr)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
restore_one_section(bfd * ibfd,asection * isec,CORE_ADDR load_offset,CORE_ADDR load_start,CORE_ADDR load_end)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       printf_filtered (_("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   printf_filtered ("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     printf_filtered (" into memory (%s to %s)\n",
429 		     paddress (target_gdbarch (),
430 			       (unsigned long) sec_start
431 			       + sec_offset + load_offset),
432 		     paddress (target_gdbarch (),
433 			       (unsigned long) sec_start + sec_offset
434 				+ load_offset + sec_load_count));
435   else
436     puts_filtered ("\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
restore_binary_file(const char * filename,CORE_ADDR load_offset,CORE_ADDR load_start,CORE_ADDR load_end)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   printf_filtered
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
restore_command(const char * args,int from_tty)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     printf_filtered ("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
_initialize_cli_dump()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