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