xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/cli/cli-dump.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /* Dump-to-file commands, for GDB, the GNU debugger.
2 
3    Copyright (C) 2002-2015 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/readline.h"
30 #include "gdbcore.h"
31 #include "cli/cli-utils.h"
32 #include "gdb_bfd.h"
33 #include "filestuff.h"
34 
35 
36 static const char *
37 scan_expression_with_cleanup (const char **cmd, const char *def)
38 {
39   if ((*cmd) == NULL || (**cmd) == '\0')
40     {
41       char *exp = xstrdup (def);
42 
43       make_cleanup (xfree, exp);
44       return exp;
45     }
46   else
47     {
48       char *exp;
49       const char *end;
50 
51       end = (*cmd) + strcspn (*cmd, " \t");
52       exp = savestring ((*cmd), end - (*cmd));
53       make_cleanup (xfree, exp);
54       (*cmd) = skip_spaces_const (end);
55       return exp;
56     }
57 }
58 
59 
60 static char *
61 scan_filename_with_cleanup (const char **cmd, const char *defname)
62 {
63   char *filename;
64   char *fullname;
65 
66   /* FIXME: Need to get the ``/a(ppend)'' flag from somewhere.  */
67 
68   /* File.  */
69   if ((*cmd) == NULL)
70     {
71       if (defname == NULL)
72 	error (_("Missing filename."));
73       filename = xstrdup (defname);
74       make_cleanup (xfree, filename);
75     }
76   else
77     {
78       /* FIXME: should parse a possibly quoted string.  */
79       const char *end;
80 
81       (*cmd) = skip_spaces_const (*cmd);
82       end = *cmd + strcspn (*cmd, " \t");
83       filename = savestring ((*cmd), end - (*cmd));
84       make_cleanup (xfree, filename);
85       (*cmd) = skip_spaces_const (end);
86     }
87   gdb_assert (filename != NULL);
88 
89   fullname = tilde_expand (filename);
90   make_cleanup (xfree, fullname);
91 
92   return fullname;
93 }
94 
95 static FILE *
96 fopen_with_cleanup (const char *filename, const char *mode)
97 {
98   FILE *file = gdb_fopen_cloexec (filename, mode);
99 
100   if (file == NULL)
101     perror_with_name (filename);
102   make_cleanup_fclose (file);
103   return file;
104 }
105 
106 static bfd *
107 bfd_openr_with_cleanup (const char *filename, const char *target)
108 {
109   bfd *ibfd;
110 
111   ibfd = gdb_bfd_openr (filename, target);
112   if (ibfd == NULL)
113     error (_("Failed to open %s: %s."), filename,
114 	   bfd_errmsg (bfd_get_error ()));
115 
116   make_cleanup_bfd_unref (ibfd);
117   if (!bfd_check_format (ibfd, bfd_object))
118     error (_("'%s' is not a recognized file format."), filename);
119 
120   return ibfd;
121 }
122 
123 static bfd *
124 bfd_openw_with_cleanup (const char *filename, const char *target,
125 			const char *mode)
126 {
127   bfd *obfd;
128 
129   if (*mode == 'w')	/* Write: create new file */
130     {
131       obfd = gdb_bfd_openw (filename, target);
132       if (obfd == NULL)
133 	error (_("Failed to open %s: %s."), filename,
134 	       bfd_errmsg (bfd_get_error ()));
135       make_cleanup_bfd_unref (obfd);
136       if (!bfd_set_format (obfd, bfd_object))
137 	error (_("bfd_openw_with_cleanup: %s."), bfd_errmsg (bfd_get_error ()));
138     }
139   else if (*mode == 'a')	/* Append to existing file.  */
140     {	/* FIXME -- doesn't work...  */
141       error (_("bfd_openw does not work with append."));
142     }
143   else
144     error (_("bfd_openw_with_cleanup: unknown mode %s."), mode);
145 
146   return obfd;
147 }
148 
149 static struct cmd_list_element *dump_cmdlist;
150 static struct cmd_list_element *append_cmdlist;
151 static struct cmd_list_element *srec_cmdlist;
152 static struct cmd_list_element *ihex_cmdlist;
153 static struct cmd_list_element *tekhex_cmdlist;
154 static struct cmd_list_element *binary_dump_cmdlist;
155 static struct cmd_list_element *binary_append_cmdlist;
156 
157 static void
158 dump_command (char *cmd, int from_tty)
159 {
160   printf_unfiltered (_("\"dump\" must be followed by a subcommand.\n\n"));
161   help_list (dump_cmdlist, "dump ", all_commands, gdb_stdout);
162 }
163 
164 static void
165 append_command (char *cmd, int from_tty)
166 {
167   printf_unfiltered (_("\"append\" must be followed by a subcommand.\n\n"));
168   help_list (dump_cmdlist, "append ", all_commands, gdb_stdout);
169 }
170 
171 static void
172 dump_binary_file (const char *filename, const char *mode,
173 		  const bfd_byte *buf, ULONGEST len)
174 {
175   FILE *file;
176   int status;
177 
178   file = fopen_with_cleanup (filename, mode);
179   status = fwrite (buf, len, 1, file);
180   if (status != 1)
181     perror_with_name (filename);
182 }
183 
184 static void
185 dump_bfd_file (const char *filename, const char *mode,
186 	       const char *target, CORE_ADDR vaddr,
187 	       const bfd_byte *buf, ULONGEST len)
188 {
189   bfd *obfd;
190   asection *osection;
191 
192   obfd = bfd_openw_with_cleanup (filename, target, mode);
193   osection = bfd_make_section_anyway (obfd, ".newsec");
194   bfd_set_section_size (obfd, osection, len);
195   bfd_set_section_vma (obfd, osection, vaddr);
196   bfd_set_section_alignment (obfd, osection, 0);
197   bfd_set_section_flags (obfd, osection, (SEC_HAS_CONTENTS
198 					  | SEC_ALLOC
199 					  | SEC_LOAD));
200   osection->entsize = 0;
201   if (!bfd_set_section_contents (obfd, osection, buf, 0, len))
202     warning (_("writing dump file '%s' (%s)"), filename,
203 	     bfd_errmsg (bfd_get_error ()));
204 }
205 
206 static void
207 dump_memory_to_file (const char *cmd, const char *mode, const char *file_format)
208 {
209   struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
210   CORE_ADDR lo;
211   CORE_ADDR hi;
212   ULONGEST count;
213   const char *filename;
214   void *buf;
215   const char *lo_exp;
216   const char *hi_exp;
217 
218   /* Open the file.  */
219   filename = scan_filename_with_cleanup (&cmd, NULL);
220 
221   /* Find the low address.  */
222   if (cmd == NULL || *cmd == '\0')
223     error (_("Missing start address."));
224   lo_exp = scan_expression_with_cleanup (&cmd, NULL);
225 
226   /* Find the second address - rest of line.  */
227   if (cmd == NULL || *cmd == '\0')
228     error (_("Missing stop address."));
229   hi_exp = cmd;
230 
231   lo = parse_and_eval_address (lo_exp);
232   hi = parse_and_eval_address (hi_exp);
233   if (hi <= lo)
234     error (_("Invalid memory address range (start >= end)."));
235   count = hi - lo;
236 
237   /* FIXME: Should use read_memory_partial() and a magic blocking
238      value.  */
239   buf = xmalloc (count);
240   make_cleanup (xfree, buf);
241   read_memory (lo, buf, count);
242 
243   /* Have everything.  Open/write the data.  */
244   if (file_format == NULL || strcmp (file_format, "binary") == 0)
245     {
246       dump_binary_file (filename, mode, buf, count);
247     }
248   else
249     {
250       dump_bfd_file (filename, mode, file_format, lo, buf, count);
251     }
252 
253   do_cleanups (old_cleanups);
254 }
255 
256 static void
257 dump_memory_command (char *cmd, char *mode)
258 {
259   dump_memory_to_file (cmd, mode, "binary");
260 }
261 
262 static void
263 dump_value_to_file (const char *cmd, const char *mode, const char *file_format)
264 {
265   struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL);
266   struct value *val;
267   const char *filename;
268 
269   /* Open the file.  */
270   filename = scan_filename_with_cleanup (&cmd, NULL);
271 
272   /* Find the value.  */
273   if (cmd == NULL || *cmd == '\0')
274     error (_("No value to %s."), *mode == 'a' ? "append" : "dump");
275   val = parse_and_eval (cmd);
276   if (val == NULL)
277     error (_("Invalid expression."));
278 
279   /* Have everything.  Open/write the data.  */
280   if (file_format == NULL || strcmp (file_format, "binary") == 0)
281     {
282       dump_binary_file (filename, mode, value_contents (val),
283 			TYPE_LENGTH (value_type (val)));
284     }
285   else
286     {
287       CORE_ADDR vaddr;
288 
289       if (VALUE_LVAL (val))
290 	{
291 	  vaddr = value_address (val);
292 	}
293       else
294 	{
295 	  vaddr = 0;
296 	  warning (_("value is not an lval: address assumed to be zero"));
297 	}
298 
299       dump_bfd_file (filename, mode, file_format, vaddr,
300 		     value_contents (val),
301 		     TYPE_LENGTH (value_type (val)));
302     }
303 
304   do_cleanups (old_cleanups);
305 }
306 
307 static void
308 dump_value_command (char *cmd, char *mode)
309 {
310   dump_value_to_file (cmd, mode, "binary");
311 }
312 
313 static void
314 dump_srec_memory (char *args, int from_tty)
315 {
316   dump_memory_to_file (args, FOPEN_WB, "srec");
317 }
318 
319 static void
320 dump_srec_value (char *args, int from_tty)
321 {
322   dump_value_to_file (args, FOPEN_WB, "srec");
323 }
324 
325 static void
326 dump_ihex_memory (char *args, int from_tty)
327 {
328   dump_memory_to_file (args, FOPEN_WB, "ihex");
329 }
330 
331 static void
332 dump_ihex_value (char *args, int from_tty)
333 {
334   dump_value_to_file (args, FOPEN_WB, "ihex");
335 }
336 
337 static void
338 dump_tekhex_memory (char *args, int from_tty)
339 {
340   dump_memory_to_file (args, FOPEN_WB, "tekhex");
341 }
342 
343 static void
344 dump_tekhex_value (char *args, int from_tty)
345 {
346   dump_value_to_file (args, FOPEN_WB, "tekhex");
347 }
348 
349 static void
350 dump_binary_memory (char *args, int from_tty)
351 {
352   dump_memory_to_file (args, FOPEN_WB, "binary");
353 }
354 
355 static void
356 dump_binary_value (char *args, int from_tty)
357 {
358   dump_value_to_file (args, FOPEN_WB, "binary");
359 }
360 
361 static void
362 append_binary_memory (char *args, int from_tty)
363 {
364   dump_memory_to_file (args, FOPEN_AB, "binary");
365 }
366 
367 static void
368 append_binary_value (char *args, int from_tty)
369 {
370   dump_value_to_file (args, FOPEN_AB, "binary");
371 }
372 
373 struct dump_context
374 {
375   void (*func) (char *cmd, char *mode);
376   char *mode;
377 };
378 
379 static void
380 call_dump_func (struct cmd_list_element *c, char *args, int from_tty)
381 {
382   struct dump_context *d = get_cmd_context (c);
383 
384   d->func (args, d->mode);
385 }
386 
387 static void
388 add_dump_command (char *name, void (*func) (char *args, char *mode),
389 		  char *descr)
390 
391 {
392   struct cmd_list_element *c;
393   struct dump_context *d;
394 
395   c = add_cmd (name, all_commands, NULL, descr, &dump_cmdlist);
396   c->completer =  filename_completer;
397   d = XNEW (struct dump_context);
398   d->func = func;
399   d->mode = FOPEN_WB;
400   set_cmd_context (c, d);
401   c->func = call_dump_func;
402 
403   c = add_cmd (name, all_commands, NULL, descr, &append_cmdlist);
404   c->completer =  filename_completer;
405   d = XNEW (struct dump_context);
406   d->func = func;
407   d->mode = FOPEN_AB;
408   set_cmd_context (c, d);
409   c->func = call_dump_func;
410 
411   /* Replace "Dump " at start of docstring with "Append " (borrowed
412      from [deleted] deprecated_add_show_from_set).  */
413   if (   c->doc[0] == 'W'
414       && c->doc[1] == 'r'
415       && c->doc[2] == 'i'
416       && c->doc[3] == 't'
417       && c->doc[4] == 'e'
418       && c->doc[5] == ' ')
419     c->doc = concat ("Append ", c->doc + 6, (char *)NULL);
420 }
421 
422 /* Opaque data for restore_section_callback.  */
423 struct callback_data {
424   CORE_ADDR load_offset;
425   CORE_ADDR load_start;
426   CORE_ADDR load_end;
427 };
428 
429 /* Function: restore_section_callback.
430 
431    Callback function for bfd_map_over_sections.
432    Selectively loads the sections into memory.  */
433 
434 static void
435 restore_section_callback (bfd *ibfd, asection *isec, void *args)
436 {
437   struct callback_data *data = args;
438   bfd_vma sec_start  = bfd_section_vma (ibfd, isec);
439   bfd_size_type size = bfd_section_size (ibfd, isec);
440   bfd_vma sec_end    = sec_start + size;
441   bfd_size_type sec_offset = 0;
442   bfd_size_type sec_load_count = size;
443   struct cleanup *old_chain;
444   gdb_byte *buf;
445   int ret;
446 
447   /* Ignore non-loadable sections, eg. from elf files.  */
448   if (!(bfd_get_section_flags (ibfd, isec) & SEC_LOAD))
449     return;
450 
451   /* Does the section overlap with the desired restore range? */
452   if (sec_end <= data->load_start
453       || (data->load_end > 0 && sec_start >= data->load_end))
454     {
455       /* No, no useable data in this section.  */
456       printf_filtered (_("skipping section %s...\n"),
457 		       bfd_section_name (ibfd, isec));
458       return;
459     }
460 
461   /* Compare section address range with user-requested
462      address range (if any).  Compute where the actual
463      transfer should start and end.  */
464   if (sec_start < data->load_start)
465     sec_offset = data->load_start - sec_start;
466   /* Size of a partial transfer.  */
467   sec_load_count -= sec_offset;
468   if (data->load_end > 0 && sec_end > data->load_end)
469     sec_load_count -= sec_end - data->load_end;
470 
471   /* Get the data.  */
472   buf = xmalloc (size);
473   old_chain = make_cleanup (xfree, buf);
474   if (!bfd_get_section_contents (ibfd, isec, buf, 0, size))
475     error (_("Failed to read bfd file %s: '%s'."), bfd_get_filename (ibfd),
476 	   bfd_errmsg (bfd_get_error ()));
477 
478   printf_filtered ("Restoring section %s (0x%lx to 0x%lx)",
479 		   bfd_section_name (ibfd, isec),
480 		   (unsigned long) sec_start,
481 		   (unsigned long) sec_end);
482 
483   if (data->load_offset != 0 || data->load_start != 0 || data->load_end != 0)
484     printf_filtered (" into memory (%s to %s)\n",
485 		     paddress (target_gdbarch (),
486 			       (unsigned long) sec_start
487 			       + sec_offset + data->load_offset),
488 		     paddress (target_gdbarch (),
489 			       (unsigned long) sec_start + sec_offset
490 				+ data->load_offset + sec_load_count));
491   else
492     puts_filtered ("\n");
493 
494   /* Write the data.  */
495   ret = target_write_memory (sec_start + sec_offset + data->load_offset,
496 			     buf + sec_offset, sec_load_count);
497   if (ret != 0)
498     warning (_("restore: memory write failed (%s)."), safe_strerror (ret));
499   do_cleanups (old_chain);
500   return;
501 }
502 
503 static void
504 restore_binary_file (const char *filename, struct callback_data *data)
505 {
506   struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
507   FILE *file = fopen_with_cleanup (filename, FOPEN_RB);
508   gdb_byte *buf;
509   long len;
510 
511   /* Get the file size for reading.  */
512   if (fseek (file, 0, SEEK_END) == 0)
513     {
514       len = ftell (file);
515       if (len < 0)
516 	perror_with_name (filename);
517     }
518   else
519     perror_with_name (filename);
520 
521   if (len <= data->load_start)
522     error (_("Start address is greater than length of binary file %s."),
523 	   filename);
524 
525   /* Chop off "len" if it exceeds the requested load_end addr.  */
526   if (data->load_end != 0 && data->load_end < len)
527     len = data->load_end;
528   /* Chop off "len" if the requested load_start addr skips some bytes.  */
529   if (data->load_start > 0)
530     len -= data->load_start;
531 
532   printf_filtered
533     ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
534      filename,
535      (unsigned long) (data->load_start + data->load_offset),
536      (unsigned long) (data->load_start + data->load_offset + len));
537 
538   /* Now set the file pos to the requested load start pos.  */
539   if (fseek (file, data->load_start, SEEK_SET) != 0)
540     perror_with_name (filename);
541 
542   /* Now allocate a buffer and read the file contents.  */
543   buf = xmalloc (len);
544   make_cleanup (xfree, buf);
545   if (fread (buf, 1, len, file) != len)
546     perror_with_name (filename);
547 
548   /* Now write the buffer into target memory.  */
549   len = target_write_memory (data->load_start + data->load_offset, buf, len);
550   if (len != 0)
551     warning (_("restore: memory write failed (%s)."), safe_strerror (len));
552   do_cleanups (cleanup);
553 }
554 
555 static void
556 restore_command (char *args_in, int from_tty)
557 {
558   char *filename;
559   struct callback_data data;
560   bfd *ibfd;
561   int binary_flag = 0;
562   const char *args = args_in;
563 
564   if (!target_has_execution)
565     noprocess ();
566 
567   data.load_offset = 0;
568   data.load_start  = 0;
569   data.load_end    = 0;
570 
571   /* Parse the input arguments.  First is filename (required).  */
572   filename = scan_filename_with_cleanup (&args, NULL);
573   if (args != NULL && *args != '\0')
574     {
575       char *binary_string = "binary";
576 
577       /* Look for optional "binary" flag.  */
578       if (strncmp (args, binary_string, strlen (binary_string)) == 0)
579 	{
580 	  binary_flag = 1;
581 	  args += strlen (binary_string);
582 	  args = skip_spaces_const (args);
583 	}
584       /* Parse offset (optional).  */
585       if (args != NULL && *args != '\0')
586       data.load_offset =
587 	parse_and_eval_address (scan_expression_with_cleanup (&args, NULL));
588       if (args != NULL && *args != '\0')
589 	{
590 	  /* Parse start address (optional).  */
591 	  data.load_start =
592 	    parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
593 	  if (args != NULL && *args != '\0')
594 	    {
595 	      /* Parse end address (optional).  */
596 	      data.load_end = parse_and_eval_long (args);
597 	      if (data.load_end <= data.load_start)
598 		error (_("Start must be less than end."));
599 	    }
600 	}
601     }
602 
603   if (info_verbose)
604     printf_filtered ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
605 		     filename, (unsigned long) data.load_offset,
606 		     (unsigned long) data.load_start,
607 		     (unsigned long) data.load_end);
608 
609   if (binary_flag)
610     {
611       restore_binary_file (filename, &data);
612     }
613   else
614     {
615       /* Open the file for loading.  */
616       ibfd = bfd_openr_with_cleanup (filename, NULL);
617 
618       /* Process the sections.  */
619       bfd_map_over_sections (ibfd, restore_section_callback, &data);
620     }
621   return;
622 }
623 
624 static void
625 srec_dump_command (char *cmd, int from_tty)
626 {
627   printf_unfiltered ("\"dump srec\" must be followed by a subcommand.\n");
628   help_list (srec_cmdlist, "dump srec ", all_commands, gdb_stdout);
629 }
630 
631 static void
632 ihex_dump_command (char *cmd, int from_tty)
633 {
634   printf_unfiltered ("\"dump ihex\" must be followed by a subcommand.\n");
635   help_list (ihex_cmdlist, "dump ihex ", all_commands, gdb_stdout);
636 }
637 
638 static void
639 tekhex_dump_command (char *cmd, int from_tty)
640 {
641   printf_unfiltered ("\"dump tekhex\" must be followed by a subcommand.\n");
642   help_list (tekhex_cmdlist, "dump tekhex ", all_commands, gdb_stdout);
643 }
644 
645 static void
646 binary_dump_command (char *cmd, int from_tty)
647 {
648   printf_unfiltered ("\"dump binary\" must be followed by a subcommand.\n");
649   help_list (binary_dump_cmdlist, "dump binary ", all_commands, gdb_stdout);
650 }
651 
652 static void
653 binary_append_command (char *cmd, int from_tty)
654 {
655   printf_unfiltered ("\"append binary\" must be followed by a subcommand.\n");
656   help_list (binary_append_cmdlist, "append binary ", all_commands,
657 	     gdb_stdout);
658 }
659 
660 extern initialize_file_ftype _initialize_cli_dump; /* -Wmissing-prototypes */
661 
662 void
663 _initialize_cli_dump (void)
664 {
665   struct cmd_list_element *c;
666 
667   add_prefix_cmd ("dump", class_vars, dump_command,
668 		  _("Dump target code/data to a local file."),
669 		  &dump_cmdlist, "dump ",
670 		  0/*allow-unknown*/,
671 		  &cmdlist);
672   add_prefix_cmd ("append", class_vars, append_command,
673 		  _("Append target code/data to a local file."),
674 		  &append_cmdlist, "append ",
675 		  0/*allow-unknown*/,
676 		  &cmdlist);
677 
678   add_dump_command ("memory", dump_memory_command, "\
679 Write contents of memory to a raw binary file.\n\
680 Arguments are FILE START STOP.  Writes the contents of memory within the\n\
681 range [START .. STOP) to the specified FILE in raw target ordered bytes.");
682 
683   add_dump_command ("value", dump_value_command, "\
684 Write the value of an expression to a raw binary file.\n\
685 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION to\n\
686 the specified FILE in raw target ordered bytes.");
687 
688   add_prefix_cmd ("srec", all_commands, srec_dump_command,
689 		  _("Write target code/data to an srec file."),
690 		  &srec_cmdlist, "dump srec ",
691 		  0 /*allow-unknown*/,
692 		  &dump_cmdlist);
693 
694   add_prefix_cmd ("ihex", all_commands, ihex_dump_command,
695 		  _("Write target code/data to an intel hex file."),
696 		  &ihex_cmdlist, "dump ihex ",
697 		  0 /*allow-unknown*/,
698 		  &dump_cmdlist);
699 
700   add_prefix_cmd ("tekhex", all_commands, tekhex_dump_command,
701 		  _("Write target code/data to a tekhex file."),
702 		  &tekhex_cmdlist, "dump tekhex ",
703 		  0 /*allow-unknown*/,
704 		  &dump_cmdlist);
705 
706   add_prefix_cmd ("binary", all_commands, binary_dump_command,
707 		  _("Write target code/data to a raw binary file."),
708 		  &binary_dump_cmdlist, "dump binary ",
709 		  0 /*allow-unknown*/,
710 		  &dump_cmdlist);
711 
712   add_prefix_cmd ("binary", all_commands, binary_append_command,
713 		  _("Append target code/data to a raw binary file."),
714 		  &binary_append_cmdlist, "append binary ",
715 		  0 /*allow-unknown*/,
716 		  &append_cmdlist);
717 
718   add_cmd ("memory", all_commands, dump_srec_memory, _("\
719 Write contents of memory to an srec file.\n\
720 Arguments are FILE START STOP.  Writes the contents of memory\n\
721 within the range [START .. STOP) to the specified FILE in srec format."),
722 	   &srec_cmdlist);
723 
724   add_cmd ("value", all_commands, dump_srec_value, _("\
725 Write the value of an expression to an srec file.\n\
726 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
727 to the specified FILE in srec format."),
728 	   &srec_cmdlist);
729 
730   add_cmd ("memory", all_commands, dump_ihex_memory, _("\
731 Write contents of memory to an ihex file.\n\
732 Arguments are FILE START STOP.  Writes the contents of memory within\n\
733 the range [START .. STOP) to the specified FILE in intel hex format."),
734 	   &ihex_cmdlist);
735 
736   add_cmd ("value", all_commands, dump_ihex_value, _("\
737 Write the value of an expression to an ihex file.\n\
738 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
739 to the specified FILE in intel hex format."),
740 	   &ihex_cmdlist);
741 
742   add_cmd ("memory", all_commands, dump_tekhex_memory, _("\
743 Write contents of memory to a tekhex file.\n\
744 Arguments are FILE START STOP.  Writes the contents of memory\n\
745 within the range [START .. STOP) to the specified FILE in tekhex format."),
746 	   &tekhex_cmdlist);
747 
748   add_cmd ("value", all_commands, dump_tekhex_value, _("\
749 Write the value of an expression to a tekhex file.\n\
750 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
751 to the specified FILE in tekhex format."),
752 	   &tekhex_cmdlist);
753 
754   add_cmd ("memory", all_commands, dump_binary_memory, _("\
755 Write contents of memory to a raw binary file.\n\
756 Arguments are FILE START STOP.  Writes the contents of memory\n\
757 within the range [START .. STOP) to the specified FILE in binary format."),
758 	   &binary_dump_cmdlist);
759 
760   add_cmd ("value", all_commands, dump_binary_value, _("\
761 Write the value of an expression to a raw binary file.\n\
762 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
763 to the specified FILE in raw target ordered bytes."),
764 	   &binary_dump_cmdlist);
765 
766   add_cmd ("memory", all_commands, append_binary_memory, _("\
767 Append contents of memory to a raw binary file.\n\
768 Arguments are FILE START STOP.  Writes the contents of memory within the\n\
769 range [START .. STOP) to the specified FILE in raw target ordered bytes."),
770 	   &binary_append_cmdlist);
771 
772   add_cmd ("value", all_commands, append_binary_value, _("\
773 Append the value of an expression to a raw binary file.\n\
774 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
775 to the specified FILE in raw target ordered bytes."),
776 	   &binary_append_cmdlist);
777 
778   c = add_com ("restore", class_vars, restore_command, _("\
779 Restore the contents of FILE to target memory.\n\
780 Arguments are FILE OFFSET START END where all except FILE are optional.\n\
781 OFFSET will be added to the base address of the file (default zero).\n\
782 If START and END are given, only the file contents within that range\n\
783 (file relative) will be restored to target memory."));
784   c->completer = filename_completer;
785   /* FIXME: completers for other commands.  */
786 }
787