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