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