2003-06-08 Andrew Cagney <cagney@redhat.com>
[external/binutils.git] / gdb / cli / cli-dump.c
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 *
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 *
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
73 do_fclose_cleanup (void *arg)
74 {
75   FILE *file = arg;
76   fclose (arg);
77 }
78
79 static struct cleanup *
80 make_cleanup_fclose (FILE *file)
81 {
82   return make_cleanup (do_fclose_cleanup, file);
83 }
84
85 char *
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 *
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 *
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 *
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
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
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
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
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
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
277 dump_memory_command (char *cmd, char *mode)
278 {
279   dump_memory_to_file (cmd, mode, "binary");
280 }
281
282 static void
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
328 dump_value_command (char *cmd, char *mode)
329 {
330   dump_value_to_file (cmd, mode, "binary");
331 }
332
333 static void
334 dump_filetype (char *cmd, char *mode, char *filetype)
335 {
336   char *suffix = cmd;
337
338   if (cmd == NULL || *cmd == '\0')
339     error ("Missing subcommand: try 'help %s %s'.", 
340            mode[0] == 'a' ? "append" : "dump", 
341            filetype);
342
343   suffix += strcspn (cmd, " \t");
344
345   if (suffix != cmd)
346     {
347       if (strncmp ("memory", cmd, suffix - cmd) == 0)
348         {
349           dump_memory_to_file (suffix, mode, filetype);
350           return;
351         }
352       else if (strncmp ("value", cmd, suffix - cmd) == 0)
353         {
354           dump_value_to_file (suffix, mode, filetype);
355           return;
356         }
357     }
358
359   error ("dump %s: unknown subcommand '%s' -- try 'value' or 'memory'.",
360          filetype, cmd);
361 }
362
363 static void
364 dump_srec_memory (char *args, int from_tty)
365 {
366   dump_memory_to_file (args, FOPEN_WB, "srec");
367 }
368
369 static void
370 dump_srec_value (char *args, int from_tty)
371 {
372   dump_value_to_file (args, FOPEN_WB, "srec");
373 }
374
375 static void
376 dump_ihex_memory (char *args, int from_tty)
377 {
378   dump_memory_to_file (args, FOPEN_WB, "ihex");
379 }
380
381 static void
382 dump_ihex_value (char *args, int from_tty)
383 {
384   dump_value_to_file (args, FOPEN_WB, "ihex");
385 }
386
387 static void
388 dump_tekhex_memory (char *args, int from_tty)
389 {
390   dump_memory_to_file (args, FOPEN_WB, "tekhex");
391 }
392
393 static void
394 dump_tekhex_value (char *args, int from_tty)
395 {
396   dump_value_to_file (args, FOPEN_WB, "tekhex");
397 }
398
399 static void
400 dump_binary_memory (char *args, int from_tty)
401 {
402   dump_memory_to_file (args, FOPEN_WB, "binary");
403 }
404
405 static void
406 dump_binary_value (char *args, int from_tty)
407 {
408   dump_value_to_file (args, FOPEN_WB, "binary");
409 }
410
411 static void
412 append_binary_memory (char *args, int from_tty)
413 {
414   dump_memory_to_file (args, FOPEN_AB, "binary");
415 }
416
417 static void
418 append_binary_value (char *args, int from_tty)
419 {
420   dump_value_to_file (args, FOPEN_AB, "binary");
421 }
422
423 struct dump_context
424 {
425   void (*func) (char *cmd, char *mode);
426   char *mode;
427 };
428
429 static void
430 call_dump_func (struct cmd_list_element *c, char *args, int from_tty)
431 {
432   struct dump_context *d = get_cmd_context (c);
433   d->func (args, d->mode);
434 }
435
436 void
437 add_dump_command (char *name, void (*func) (char *args, char *mode),
438                   char *descr)
439
440 {
441   struct cmd_list_element *c;
442   struct dump_context *d;
443
444   c = add_cmd (name, all_commands, NULL, descr, &dump_cmdlist);
445   c->completer =  filename_completer;
446   d = XMALLOC (struct dump_context);
447   d->func = func;
448   d->mode = FOPEN_WB;
449   set_cmd_context (c, d);
450   c->func = call_dump_func;
451
452   c = add_cmd (name, all_commands, NULL, descr, &append_cmdlist);
453   c->completer =  filename_completer;
454   d = XMALLOC (struct dump_context);
455   d->func = func;
456   d->mode = FOPEN_AB;
457   set_cmd_context (c, d);
458   c->func = call_dump_func;
459
460   /* Replace "Dump " at start of docstring with "Append "
461      (borrowed from add_show_from_set).  */
462   if (   c->doc[0] == 'W' 
463       && c->doc[1] == 'r' 
464       && c->doc[2] == 'i'
465       && c->doc[3] == 't' 
466       && c->doc[4] == 'e'
467       && c->doc[5] == ' ')
468     c->doc = concat ("Append ", c->doc + 6, NULL);
469 }
470
471 /* Opaque data for restore_section_callback. */
472 struct callback_data {
473   unsigned long load_offset;
474   CORE_ADDR load_start;
475   CORE_ADDR load_end;
476 };
477
478 /* Function: restore_section_callback.
479
480    Callback function for bfd_map_over_sections.
481    Selectively loads the sections into memory.  */
482
483 static void
484 restore_section_callback (bfd *ibfd, asection *isec, void *args)
485 {
486   struct callback_data *data = args;
487   bfd_vma sec_start  = bfd_section_vma (ibfd, isec);
488   bfd_size_type size = bfd_section_size (ibfd, isec);
489   bfd_vma sec_end    = sec_start + size;
490   bfd_size_type sec_offset = 0;
491   bfd_size_type sec_load_count = size;
492   struct cleanup *old_chain;
493   char *buf;
494   int ret;
495
496   /* Ignore non-loadable sections, eg. from elf files. */
497   if (!(bfd_get_section_flags (ibfd, isec) & SEC_LOAD))
498     return;
499
500   /* Does the section overlap with the desired restore range? */
501   if (sec_end <= data->load_start 
502       || (data->load_end > 0 && sec_start >= data->load_end))
503     {
504       /* No, no useable data in this section. */
505       printf_filtered ("skipping section %s...\n", 
506                        bfd_section_name (ibfd, isec));
507       return;
508     }
509
510   /* Compare section address range with user-requested
511      address range (if any).  Compute where the actual
512      transfer should start and end.  */
513   if (sec_start < data->load_start)
514     sec_offset = data->load_start - sec_start;
515   /* Size of a partial transfer: */
516   sec_load_count -= sec_offset;
517   if (data->load_end > 0 && sec_end > data->load_end)
518     sec_load_count -= sec_end - data->load_end;
519
520   /* Get the data.  */
521   buf = xmalloc (size);
522   old_chain = make_cleanup (xfree, buf);
523   if (!bfd_get_section_contents (ibfd, isec, buf, 0, size))
524     error ("Failed to read bfd file %s: '%s'.", bfd_get_filename (ibfd), 
525            bfd_errmsg (bfd_get_error ()));
526
527   printf_filtered ("Restoring section %s (0x%lx to 0x%lx)",
528                    bfd_section_name (ibfd, isec), 
529                    (unsigned long) sec_start, 
530                    (unsigned long) sec_end);
531
532   if (data->load_offset != 0 || data->load_start != 0 || data->load_end != 0)
533     printf_filtered (" into memory (0x%s to 0x%s)\n", 
534                      paddr_nz ((unsigned long) sec_start 
535                                + sec_offset + data->load_offset), 
536                      paddr_nz ((unsigned long) sec_start + sec_offset 
537                        + data->load_offset + sec_load_count));
538   else
539     puts_filtered ("\n");
540
541   /* Write the data.  */
542   ret = target_write_memory (sec_start + sec_offset + data->load_offset, 
543                              buf + sec_offset, sec_load_count);
544   if (ret != 0)
545     warning ("restore: memory write failed (%s).", safe_strerror (ret));
546   do_cleanups (old_chain);
547   return;
548 }
549
550 static void
551 restore_binary_file (char *filename, struct callback_data *data)
552 {
553   FILE *file = fopen_with_cleanup (filename, FOPEN_RB);
554   int status;
555   char *buf;
556   long len;
557
558   /* Get the file size for reading.  */
559   if (fseek (file, 0, SEEK_END) == 0)
560     len = ftell (file);
561   else
562     perror_with_name (filename);
563
564   if (len <= data->load_start)
565     error ("Start address is greater than length of binary file %s.", 
566            filename);
567
568   /* Chop off "len" if it exceeds the requested load_end addr. */
569   if (data->load_end != 0 && data->load_end < len)
570     len = data->load_end;
571   /* Chop off "len" if the requested load_start addr skips some bytes. */
572   if (data->load_start > 0)
573     len -= data->load_start;
574
575   printf_filtered 
576     ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n", 
577      filename, 
578      (unsigned long) data->load_start + data->load_offset, 
579      (unsigned long) data->load_start + data->load_offset + len);
580
581   /* Now set the file pos to the requested load start pos.  */
582   if (fseek (file, data->load_start, SEEK_SET) != 0)
583     perror_with_name (filename);
584
585   /* Now allocate a buffer and read the file contents.  */
586   buf = xmalloc (len);
587   make_cleanup (xfree, buf);
588   if (fread (buf, 1, len, file) != len)
589     perror_with_name (filename);
590
591   /* Now write the buffer into target memory. */
592   len = target_write_memory (data->load_start + data->load_offset, buf, len);
593   if (len != 0)
594     warning ("restore: memory write failed (%s).", safe_strerror (len));
595   return;
596 }
597
598 static void
599 restore_command (char *args, int from_tty)
600 {
601   char *filename;
602   struct callback_data data;
603   bfd *ibfd;
604   int binary_flag = 0;
605
606   if (!target_has_execution)
607     noprocess ();
608
609   data.load_offset = 0;
610   data.load_start  = 0;
611   data.load_end    = 0;
612
613   /* Parse the input arguments.  First is filename (required). */
614   filename = scan_filename_with_cleanup (&args, NULL);
615   if (args != NULL && *args != '\0')
616     {
617       char *binary_string = "binary";
618
619       /* Look for optional "binary" flag.  */
620       if (strncmp (args, binary_string, strlen (binary_string)) == 0)
621         {
622           binary_flag = 1;
623           args += strlen (binary_string);
624           args = skip_spaces (args);
625         }
626       /* Parse offset (optional). */
627       if (args != NULL && *args != '\0')
628       data.load_offset = 
629         parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
630       if (args != NULL && *args != '\0')
631         {
632           /* Parse start address (optional). */
633           data.load_start = 
634             parse_and_eval_long (scan_expression_with_cleanup (&args, NULL));
635           if (args != NULL && *args != '\0')
636             {
637               /* Parse end address (optional). */
638               data.load_end = parse_and_eval_long (args);
639               if (data.load_end <= data.load_start)
640                 error ("Start must be less than end.");
641             }
642         }
643     }
644
645   if (info_verbose)
646     printf_filtered ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
647                      filename, (unsigned long) data.load_offset, 
648                      (unsigned long) data.load_start, 
649                      (unsigned long) data.load_end);
650
651   if (binary_flag)
652     {
653       restore_binary_file (filename, &data);
654     }
655   else
656     {
657       /* Open the file for loading. */
658       ibfd = bfd_openr_with_cleanup (filename, NULL);
659
660       /* Process the sections. */
661       bfd_map_over_sections (ibfd, restore_section_callback, &data);
662     }
663   return;
664 }
665
666 static void
667 srec_dump_command (char *cmd, int from_tty)
668 {
669   printf_unfiltered ("\"dump srec\" must be followed by a subcommand.\n");
670   help_list (srec_cmdlist, "dump srec ", -1, gdb_stdout);
671 }
672
673 static void
674 ihex_dump_command (char *cmd, int from_tty)
675 {
676   printf_unfiltered ("\"dump ihex\" must be followed by a subcommand.\n");
677   help_list (ihex_cmdlist, "dump ihex ", -1, gdb_stdout);
678 }
679
680 static void
681 tekhex_dump_command (char *cmd, int from_tty)
682 {
683   printf_unfiltered ("\"dump tekhex\" must be followed by a subcommand.\n");
684   help_list (tekhex_cmdlist, "dump tekhex ", -1, gdb_stdout);
685 }
686
687 static void
688 binary_dump_command (char *cmd, int from_tty)
689 {
690   printf_unfiltered ("\"dump binary\" must be followed by a subcommand.\n");
691   help_list (binary_dump_cmdlist, "dump binary ", -1, gdb_stdout);
692 }
693
694 static void
695 binary_append_command (char *cmd, int from_tty)
696 {
697   printf_unfiltered ("\"append binary\" must be followed by a subcommand.\n");
698   help_list (binary_append_cmdlist, "append binary ", -1, gdb_stdout);
699 }
700
701 extern initialize_file_ftype _initialize_cli_dump; /* -Wmissing-prototypes */
702
703 void
704 _initialize_cli_dump (void)
705 {
706   struct cmd_list_element *c;
707   add_prefix_cmd ("dump", class_vars, dump_command, "\
708 Dump target code/data to a local file.",
709                   &dump_cmdlist, "dump ",
710                   0/*allow-unknown*/,
711                   &cmdlist);
712   add_prefix_cmd ("append", class_vars, append_command, "\
713 Append target code/data to a local file.",
714                   &append_cmdlist, "append ",
715                   0/*allow-unknown*/,
716                   &cmdlist);
717
718   add_dump_command ("memory", dump_memory_command, "\
719 Write contents of memory to a raw binary file.\n\
720 Arguments are FILE START STOP.  Writes the contents of memory within the\n\
721 range [START .. STOP) to the specifed FILE in raw target ordered bytes.");
722
723   add_dump_command ("value", dump_value_command, "\
724 Write the value of an expression to a raw binary file.\n\
725 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION to\n\
726 the specified FILE in raw target ordered bytes.");
727
728   add_prefix_cmd ("srec", all_commands, srec_dump_command, "\
729 Write target code/data to an srec file.",
730                   &srec_cmdlist, "dump srec ", 
731                   0 /*allow-unknown*/, 
732                   &dump_cmdlist);
733
734   add_prefix_cmd ("ihex", all_commands, ihex_dump_command, "\
735 Write target code/data to an intel hex file.",
736                   &ihex_cmdlist, "dump ihex ", 
737                   0 /*allow-unknown*/, 
738                   &dump_cmdlist);
739
740   add_prefix_cmd ("tekhex", all_commands, tekhex_dump_command, "\
741 Write target code/data to a tekhex file.",
742                   &tekhex_cmdlist, "dump tekhex ", 
743                   0 /*allow-unknown*/, 
744                   &dump_cmdlist);
745
746   add_prefix_cmd ("binary", all_commands, binary_dump_command, "\
747 Write target code/data to a raw binary file.",
748                   &binary_dump_cmdlist, "dump binary ", 
749                   0 /*allow-unknown*/, 
750                   &dump_cmdlist);
751
752   add_prefix_cmd ("binary", all_commands, binary_append_command, "\
753 Append target code/data to a raw binary file.",
754                   &binary_append_cmdlist, "append binary ", 
755                   0 /*allow-unknown*/, 
756                   &append_cmdlist);
757
758   add_cmd ("memory", all_commands, dump_srec_memory, "\
759 Write contents of memory to an srec file.\n\
760 Arguments are FILE START STOP.  Writes the contents of memory\n\
761 within the range [START .. STOP) to the specifed FILE in srec format.",
762            &srec_cmdlist);
763
764   add_cmd ("value", all_commands, dump_srec_value, "\
765 Write the value of an expression to an srec file.\n\
766 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
767 to the specified FILE in srec format.",
768            &srec_cmdlist);
769
770   add_cmd ("memory", all_commands, dump_ihex_memory, "\
771 Write contents of memory to an ihex file.\n\
772 Arguments are FILE START STOP.  Writes the contents of memory within\n\
773 the range [START .. STOP) to the specifed FILE in intel hex format.",
774            &ihex_cmdlist);
775
776   add_cmd ("value", all_commands, dump_ihex_value, "\
777 Write the value of an expression to an ihex file.\n\
778 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
779 to the specified FILE in intel hex format.",
780            &ihex_cmdlist);
781
782   add_cmd ("memory", all_commands, dump_tekhex_memory, "\
783 Write contents of memory to a tekhex file.\n\
784 Arguments are FILE START STOP.  Writes the contents of memory\n\
785 within the range [START .. STOP) to the specifed FILE in tekhex format.",
786            &tekhex_cmdlist);
787
788   add_cmd ("value", all_commands, dump_tekhex_value, "\
789 Write the value of an expression to a tekhex file.\n\
790 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
791 to the specified FILE in tekhex format.",
792            &tekhex_cmdlist);
793
794   add_cmd ("memory", all_commands, dump_binary_memory, "\
795 Write contents of memory to a raw binary file.\n\
796 Arguments are FILE START STOP.  Writes the contents of memory\n\
797 within the range [START .. STOP) to the specifed FILE in binary format.",
798            &binary_dump_cmdlist);
799
800   add_cmd ("value", all_commands, dump_binary_value, "\
801 Write the value of an expression to a raw binary file.\n\
802 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
803 to the specified FILE in raw target ordered bytes.",
804            &binary_dump_cmdlist);
805
806   add_cmd ("memory", all_commands, append_binary_memory, "\
807 Append contents of memory to a raw binary file.\n\
808 Arguments are FILE START STOP.  Writes the contents of memory within the\n\
809 range [START .. STOP) to the specifed FILE in raw target ordered bytes.",
810            &binary_append_cmdlist);
811
812   add_cmd ("value", all_commands, append_binary_value, "\
813 Append the value of an expression to a raw binary file.\n\
814 Arguments are FILE EXPRESSION.  Writes the value of EXPRESSION\n\
815 to the specified FILE in raw target ordered bytes.",
816            &binary_append_cmdlist);
817
818   c = add_com ("restore", class_vars, restore_command, 
819                "Restore the contents of FILE to target memory.\n\
820 Arguments are FILE OFFSET START END where all except FILE are optional.\n\
821 OFFSET will be added to the base address of the file (default zero).\n\
822 If START and END are given, only the file contents within that range\n\
823 (file relative) will be restored to target memory.");
824   c->completer = filename_completer;
825   /* FIXME: completers for other commands. */
826 }