gdb: remove target_gdbarch
[binutils-gdb.git] / gdb / cli / cli-dump.c
1 /* Dump-to-file commands, for GDB, the GNU debugger.
2
3 Copyright (C) 2002-2023 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 #include "inferior.h"
37
38 static gdb::unique_xmalloc_ptr<char>
39 scan_expression (const char **cmd, const char *def)
40 {
41 if ((*cmd) == NULL || (**cmd) == '\0')
42 return make_unique_xstrdup (def);
43 else
44 {
45 char *exp;
46 const char *end;
47
48 end = (*cmd) + strcspn (*cmd, " \t");
49 exp = savestring ((*cmd), end - (*cmd));
50 (*cmd) = skip_spaces (end);
51 return gdb::unique_xmalloc_ptr<char> (exp);
52 }
53 }
54
55
56 static gdb::unique_xmalloc_ptr<char>
57 scan_filename (const char **cmd, const char *defname)
58 {
59 gdb::unique_xmalloc_ptr<char> filename;
60
61 /* FIXME: Need to get the ``/a(ppend)'' flag from somewhere. */
62
63 /* File. */
64 if ((*cmd) == NULL)
65 {
66 if (defname == NULL)
67 error (_("Missing filename."));
68 filename.reset (xstrdup (defname));
69 }
70 else
71 {
72 /* FIXME: should parse a possibly quoted string. */
73 const char *end;
74
75 (*cmd) = skip_spaces (*cmd);
76 end = *cmd + strcspn (*cmd, " \t");
77 filename.reset (savestring ((*cmd), end - (*cmd)));
78 (*cmd) = skip_spaces (end);
79 }
80 gdb_assert (filename != NULL);
81
82 return gdb::unique_xmalloc_ptr<char> (tilde_expand (filename.get ()));
83 }
84
85 static gdb_bfd_ref_ptr
86 bfd_openr_or_error (const char *filename, const char *target)
87 {
88 gdb_bfd_ref_ptr ibfd (gdb_bfd_openr (filename, target));
89 if (ibfd == NULL)
90 error (_("Failed to open %s: %s."), filename,
91 bfd_errmsg (bfd_get_error ()));
92
93 if (!bfd_check_format (ibfd.get (), bfd_object))
94 error (_("'%s' is not a recognized file format."), filename);
95
96 return ibfd;
97 }
98
99 static gdb_bfd_ref_ptr
100 bfd_openw_or_error (const char *filename, const char *target, const char *mode)
101 {
102 gdb_bfd_ref_ptr obfd;
103
104 if (*mode == 'w') /* Write: create new file */
105 {
106 obfd = gdb_bfd_openw (filename, target);
107 if (obfd == NULL)
108 error (_("Failed to open %s: %s."), filename,
109 bfd_errmsg (bfd_get_error ()));
110 if (!bfd_set_format (obfd.get (), bfd_object))
111 error (_("bfd_openw_or_error: %s."), bfd_errmsg (bfd_get_error ()));
112 }
113 else if (*mode == 'a') /* Append to existing file. */
114 { /* FIXME -- doesn't work... */
115 error (_("bfd_openw does not work with append."));
116 }
117 else
118 error (_("bfd_openw_or_error: unknown mode %s."), mode);
119
120 return obfd;
121 }
122
123 static struct cmd_list_element *dump_cmdlist;
124 static struct cmd_list_element *append_cmdlist;
125 static struct cmd_list_element *srec_cmdlist;
126 static struct cmd_list_element *ihex_cmdlist;
127 static struct cmd_list_element *verilog_cmdlist;
128 static struct cmd_list_element *tekhex_cmdlist;
129 static struct cmd_list_element *binary_dump_cmdlist;
130 static struct cmd_list_element *binary_append_cmdlist;
131
132 static void
133 dump_binary_file (const char *filename, const char *mode,
134 const bfd_byte *buf, ULONGEST len)
135 {
136 int status;
137
138 gdb_file_up file = gdb_fopen_cloexec (filename, mode);
139 if (file == nullptr)
140 perror_with_name (filename);
141
142 status = fwrite (buf, len, 1, file.get ());
143 if (status != 1)
144 perror_with_name (filename);
145 }
146
147 static void
148 dump_bfd_file (const char *filename, const char *mode,
149 const char *target, CORE_ADDR vaddr,
150 const bfd_byte *buf, ULONGEST len)
151 {
152 asection *osection;
153
154 gdb_bfd_ref_ptr obfd (bfd_openw_or_error (filename, target, mode));
155 osection = bfd_make_section_anyway (obfd.get (), ".newsec");
156 bfd_set_section_size (osection, len);
157 bfd_set_section_vma (osection, vaddr);
158 bfd_set_section_alignment (osection, 0);
159 bfd_set_section_flags (osection, (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD));
160 osection->entsize = 0;
161 if (!bfd_set_section_contents (obfd.get (), osection, buf, 0, len))
162 warning (_("writing dump file '%s' (%s)"), filename,
163 bfd_errmsg (bfd_get_error ()));
164 }
165
166 static void
167 dump_memory_to_file (const char *cmd, const char *mode, const char *file_format)
168 {
169 CORE_ADDR lo;
170 CORE_ADDR hi;
171 ULONGEST count;
172 const char *hi_exp;
173
174 /* Open the file. */
175 gdb::unique_xmalloc_ptr<char> filename = scan_filename (&cmd, NULL);
176
177 /* Find the low address. */
178 if (cmd == NULL || *cmd == '\0')
179 error (_("Missing start address."));
180 gdb::unique_xmalloc_ptr<char> lo_exp = scan_expression (&cmd, NULL);
181
182 /* Find the second address - rest of line. */
183 if (cmd == NULL || *cmd == '\0')
184 error (_("Missing stop address."));
185 hi_exp = cmd;
186
187 lo = parse_and_eval_address (lo_exp.get ());
188 hi = parse_and_eval_address (hi_exp);
189 if (hi <= lo)
190 error (_("Invalid memory address range (start >= end)."));
191 count = hi - lo;
192
193 /* FIXME: Should use read_memory_partial() and a magic blocking
194 value. */
195 gdb::byte_vector buf (count);
196 read_memory (lo, buf.data (), count);
197
198 /* Have everything. Open/write the data. */
199 if (file_format == NULL || strcmp (file_format, "binary") == 0)
200 dump_binary_file (filename.get (), mode, buf.data (), count);
201 else
202 dump_bfd_file (filename.get (), mode, file_format, lo, buf.data (), count);
203 }
204
205 static void
206 dump_memory_command (const char *cmd, const char *mode)
207 {
208 dump_memory_to_file (cmd, mode, "binary");
209 }
210
211 static void
212 dump_value_to_file (const char *cmd, const char *mode, const char *file_format)
213 {
214 struct value *val;
215
216 /* Open the file. */
217 gdb::unique_xmalloc_ptr<char> filename = scan_filename (&cmd, NULL);
218
219 /* Find the value. */
220 if (cmd == NULL || *cmd == '\0')
221 error (_("No value to %s."), *mode == 'a' ? "append" : "dump");
222 val = parse_and_eval (cmd);
223 if (val == NULL)
224 error (_("Invalid expression."));
225
226 /* Have everything. Open/write the data. */
227 if (file_format == NULL || strcmp (file_format, "binary") == 0)
228 dump_binary_file (filename.get (), mode, val->contents ().data (),
229 val->type ()->length ());
230 else
231 {
232 CORE_ADDR vaddr;
233
234 if (val->lval ())
235 {
236 vaddr = val->address ();
237 }
238 else
239 {
240 vaddr = 0;
241 warning (_("value is not an lval: address assumed to be zero"));
242 }
243
244 dump_bfd_file (filename.get (), mode, file_format, vaddr,
245 val->contents ().data (),
246 val->type ()->length ());
247 }
248 }
249
250 static void
251 dump_value_command (const char *cmd, const char *mode)
252 {
253 dump_value_to_file (cmd, mode, "binary");
254 }
255
256 static void
257 dump_srec_memory (const char *args, int from_tty)
258 {
259 dump_memory_to_file (args, FOPEN_WB, "srec");
260 }
261
262 static void
263 dump_srec_value (const char *args, int from_tty)
264 {
265 dump_value_to_file (args, FOPEN_WB, "srec");
266 }
267
268 static void
269 dump_ihex_memory (const char *args, int from_tty)
270 {
271 dump_memory_to_file (args, FOPEN_WB, "ihex");
272 }
273
274 static void
275 dump_ihex_value (const char *args, int from_tty)
276 {
277 dump_value_to_file (args, FOPEN_WB, "ihex");
278 }
279
280 static void
281 dump_verilog_memory (const char *args, int from_tty)
282 {
283 dump_memory_to_file (args, FOPEN_WB, "verilog");
284 }
285
286 static void
287 dump_verilog_value (const char *args, int from_tty)
288 {
289 dump_value_to_file (args, FOPEN_WB, "verilog");
290 }
291
292 static void
293 dump_tekhex_memory (const char *args, int from_tty)
294 {
295 dump_memory_to_file (args, FOPEN_WB, "tekhex");
296 }
297
298 static void
299 dump_tekhex_value (const char *args, int from_tty)
300 {
301 dump_value_to_file (args, FOPEN_WB, "tekhex");
302 }
303
304 static void
305 dump_binary_memory (const char *args, int from_tty)
306 {
307 dump_memory_to_file (args, FOPEN_WB, "binary");
308 }
309
310 static void
311 dump_binary_value (const char *args, int from_tty)
312 {
313 dump_value_to_file (args, FOPEN_WB, "binary");
314 }
315
316 static void
317 append_binary_memory (const char *args, int from_tty)
318 {
319 dump_memory_to_file (args, FOPEN_AB, "binary");
320 }
321
322 static void
323 append_binary_value (const char *args, int from_tty)
324 {
325 dump_value_to_file (args, FOPEN_AB, "binary");
326 }
327
328 struct dump_context
329 {
330 void (*func) (const char *cmd, const char *mode);
331 const char *mode;
332 };
333
334 static void
335 call_dump_func (const char *args, int from_tty, cmd_list_element *c)
336 {
337 struct dump_context *d = (struct dump_context *) c->context ();
338
339 d->func (args, d->mode);
340 }
341
342 static void
343 add_dump_command (const char *name,
344 void (*func) (const char *args, const char *mode),
345 const char *descr)
346
347 {
348 struct cmd_list_element *c;
349 struct dump_context *d;
350
351 c = add_cmd (name, all_commands, descr, &dump_cmdlist);
352 c->completer = filename_completer;
353 d = XNEW (struct dump_context);
354 d->func = func;
355 d->mode = FOPEN_WB;
356 c->set_context (d);
357 c->func = call_dump_func;
358
359 c = add_cmd (name, all_commands, descr, &append_cmdlist);
360 c->completer = filename_completer;
361 d = XNEW (struct dump_context);
362 d->func = func;
363 d->mode = FOPEN_AB;
364 c->set_context (d);
365 c->func = call_dump_func;
366
367 /* Replace "Dump " at start of docstring with "Append " (borrowed
368 from [deleted] deprecated_add_show_from_set). */
369 if ( c->doc[0] == 'W'
370 && c->doc[1] == 'r'
371 && c->doc[2] == 'i'
372 && c->doc[3] == 't'
373 && c->doc[4] == 'e'
374 && c->doc[5] == ' ')
375 c->doc = concat ("Append ", c->doc + 6, (char *)NULL);
376 }
377
378 /* Selectively loads the sections into memory. */
379
380 static void
381 restore_one_section (bfd *ibfd, asection *isec,
382 CORE_ADDR load_offset,
383 CORE_ADDR load_start,
384 CORE_ADDR load_end)
385 {
386 bfd_vma sec_start = bfd_section_vma (isec);
387 bfd_size_type size = bfd_section_size (isec);
388 bfd_vma sec_end = sec_start + size;
389 bfd_size_type sec_offset = 0;
390 bfd_size_type sec_load_count = size;
391 int ret;
392
393 /* Ignore non-loadable sections, eg. from elf files. */
394 if (!(bfd_section_flags (isec) & SEC_LOAD))
395 return;
396
397 /* Does the section overlap with the desired restore range? */
398 if (sec_end <= load_start
399 || (load_end > 0 && sec_start >= load_end))
400 {
401 /* No, no useable data in this section. */
402 gdb_printf (_("skipping section %s...\n"),
403 bfd_section_name (isec));
404 return;
405 }
406
407 /* Compare section address range with user-requested
408 address range (if any). Compute where the actual
409 transfer should start and end. */
410 if (sec_start < load_start)
411 sec_offset = load_start - sec_start;
412 /* Size of a partial transfer. */
413 sec_load_count -= sec_offset;
414 if (load_end > 0 && sec_end > load_end)
415 sec_load_count -= sec_end - load_end;
416
417 /* Get the data. */
418 gdb::byte_vector buf (size);
419 if (!bfd_get_section_contents (ibfd, isec, buf.data (), 0, size))
420 error (_("Failed to read bfd file %s: '%s'."), bfd_get_filename (ibfd),
421 bfd_errmsg (bfd_get_error ()));
422
423 gdb_printf ("Restoring section %s (0x%lx to 0x%lx)",
424 bfd_section_name (isec),
425 (unsigned long) sec_start,
426 (unsigned long) sec_end);
427
428 if (load_offset != 0 || load_start != 0 || load_end != 0)
429 gdb_printf (" into memory (%s to %s)\n",
430 paddress (current_inferior ()->arch (),
431 (unsigned long) sec_start
432 + sec_offset + load_offset),
433 paddress (current_inferior ()->arch (),
434 (unsigned long) sec_start + sec_offset
435 + load_offset + sec_load_count));
436 else
437 gdb_puts ("\n");
438
439 /* Write the data. */
440 ret = target_write_memory (sec_start + sec_offset + load_offset,
441 &buf[sec_offset], sec_load_count);
442 if (ret != 0)
443 warning (_("restore: memory write failed (%s)."), safe_strerror (ret));
444 }
445
446 static void
447 restore_binary_file (const char *filename, CORE_ADDR load_offset,
448 CORE_ADDR load_start, CORE_ADDR load_end)
449
450 {
451 gdb_file_up file = gdb_fopen_cloexec (filename, FOPEN_RB);
452 long len;
453
454 if (file == NULL)
455 error (_("Failed to open %s: %s"), filename, safe_strerror (errno));
456
457 /* Get the file size for reading. */
458 if (fseek (file.get (), 0, SEEK_END) == 0)
459 {
460 len = ftell (file.get ());
461 if (len < 0)
462 perror_with_name (filename);
463 }
464 else
465 perror_with_name (filename);
466
467 if (len <= load_start)
468 error (_("Start address is greater than length of binary file %s."),
469 filename);
470
471 /* Chop off "len" if it exceeds the requested load_end addr. */
472 if (load_end != 0 && load_end < len)
473 len = load_end;
474 /* Chop off "len" if the requested load_start addr skips some bytes. */
475 if (load_start > 0)
476 len -= load_start;
477
478 gdb_printf
479 ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
480 filename,
481 (unsigned long) (load_start + load_offset),
482 (unsigned long) (load_start + load_offset + len));
483
484 /* Now set the file pos to the requested load start pos. */
485 if (fseek (file.get (), load_start, SEEK_SET) != 0)
486 perror_with_name (filename);
487
488 /* Now allocate a buffer and read the file contents. */
489 gdb::byte_vector buf (len);
490 if (fread (buf.data (), 1, len, file.get ()) != len)
491 perror_with_name (filename);
492
493 /* Now write the buffer into target memory. */
494 len = target_write_memory (load_start + load_offset, buf.data (), len);
495 if (len != 0)
496 warning (_("restore: memory write failed (%s)."), safe_strerror (len));
497 }
498
499 static void
500 restore_command (const char *args, int from_tty)
501 {
502 int binary_flag = 0;
503
504 if (!target_has_execution ())
505 noprocess ();
506
507 CORE_ADDR load_offset = 0;
508 CORE_ADDR load_start = 0;
509 CORE_ADDR load_end = 0;
510
511 /* Parse the input arguments. First is filename (required). */
512 gdb::unique_xmalloc_ptr<char> filename = scan_filename (&args, NULL);
513 if (args != NULL && *args != '\0')
514 {
515 static const char binary_string[] = "binary";
516
517 /* Look for optional "binary" flag. */
518 if (startswith (args, binary_string))
519 {
520 binary_flag = 1;
521 args += strlen (binary_string);
522 args = skip_spaces (args);
523 }
524 /* Parse offset (optional). */
525 if (args != NULL && *args != '\0')
526 load_offset
527 = (binary_flag
528 ? parse_and_eval_address (scan_expression (&args, NULL).get ())
529 : parse_and_eval_long (scan_expression (&args, NULL).get ()));
530 if (args != NULL && *args != '\0')
531 {
532 /* Parse start address (optional). */
533 load_start =
534 parse_and_eval_long (scan_expression (&args, NULL).get ());
535 if (args != NULL && *args != '\0')
536 {
537 /* Parse end address (optional). */
538 load_end = parse_and_eval_long (args);
539 if (load_end <= load_start)
540 error (_("Start must be less than end."));
541 }
542 }
543 }
544
545 if (info_verbose)
546 gdb_printf ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
547 filename.get (), (unsigned long) load_offset,
548 (unsigned long) load_start,
549 (unsigned long) load_end);
550
551 if (binary_flag)
552 {
553 restore_binary_file (filename.get (), load_offset, load_start,
554 load_end);
555 }
556 else
557 {
558 /* Open the file for loading. */
559 gdb_bfd_ref_ptr ibfd (bfd_openr_or_error (filename.get (), NULL));
560
561 /* Process the sections. */
562 for (asection *sect : gdb_bfd_sections (ibfd))
563 restore_one_section (ibfd.get (), sect, load_offset, load_start,
564 load_end);
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,
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,
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,
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,
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,
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,
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,
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,
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 }