1 /* Dump-to-file commands, for GDB, the GNU debugger.
3 Copyright (C) 2002-2022 Free Software Foundation, Inc.
5 Contributed by Red Hat.
7 This file is part of GDB.
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.
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.
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/>. */
23 #include "cli/cli-decode.h"
24 #include "cli/cli-cmds.h"
26 #include "completer.h"
29 #include "readline/tilde.h"
31 #include "cli/cli-utils.h"
33 #include "gdbsupport/filestuff.h"
34 #include "gdbsupport/byte-vector.h"
37 static gdb::unique_xmalloc_ptr
<char>
38 scan_expression (const char **cmd
, const char *def
)
40 if ((*cmd
) == NULL
|| (**cmd
) == '\0')
41 return make_unique_xstrdup (def
);
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
);
55 static gdb::unique_xmalloc_ptr
<char>
56 scan_filename (const char **cmd
, const char *defname
)
58 gdb::unique_xmalloc_ptr
<char> filename
;
60 /* FIXME: Need to get the ``/a(ppend)'' flag from somewhere. */
66 error (_("Missing filename."));
67 filename
.reset (xstrdup (defname
));
71 /* FIXME: should parse a possibly quoted string. */
74 (*cmd
) = skip_spaces (*cmd
);
75 end
= *cmd
+ strcspn (*cmd
, " \t");
76 filename
.reset (savestring ((*cmd
), end
- (*cmd
)));
77 (*cmd
) = skip_spaces (end
);
79 gdb_assert (filename
!= NULL
);
81 return gdb::unique_xmalloc_ptr
<char> (tilde_expand (filename
.get ()));
84 static gdb_bfd_ref_ptr
85 bfd_openr_or_error (const char *filename
, const char *target
)
87 gdb_bfd_ref_ptr
ibfd (gdb_bfd_openr (filename
, target
));
89 error (_("Failed to open %s: %s."), filename
,
90 bfd_errmsg (bfd_get_error ()));
92 if (!bfd_check_format (ibfd
.get (), bfd_object
))
93 error (_("'%s' is not a recognized file format."), filename
);
98 static gdb_bfd_ref_ptr
99 bfd_openw_or_error (const char *filename
, const char *target
, const char *mode
)
101 gdb_bfd_ref_ptr obfd
;
103 if (*mode
== 'w') /* Write: create new file */
105 obfd
= gdb_bfd_openw (filename
, target
);
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 ()));
112 else if (*mode
== 'a') /* Append to existing file. */
113 { /* FIXME -- doesn't work... */
114 error (_("bfd_openw does not work with append."));
117 error (_("bfd_openw_or_error: unknown mode %s."), mode
);
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
;
132 dump_binary_file (const char *filename
, const char *mode
,
133 const bfd_byte
*buf
, ULONGEST len
)
137 gdb_file_up file
= gdb_fopen_cloexec (filename
, mode
);
139 perror_with_name (filename
);
141 status
= fwrite (buf
, len
, 1, file
.get ());
143 perror_with_name (filename
);
147 dump_bfd_file (const char *filename
, const char *mode
,
148 const char *target
, CORE_ADDR vaddr
,
149 const bfd_byte
*buf
, ULONGEST len
)
153 gdb_bfd_ref_ptr
obfd (bfd_openw_or_error (filename
, target
, mode
));
154 osection
= bfd_make_section_anyway (obfd
.get (), ".newsec");
155 bfd_set_section_size (osection
, len
);
156 bfd_set_section_vma (osection
, vaddr
);
157 bfd_set_section_alignment (osection
, 0);
158 bfd_set_section_flags (osection
, (SEC_HAS_CONTENTS
| SEC_ALLOC
| SEC_LOAD
));
159 osection
->entsize
= 0;
160 if (!bfd_set_section_contents (obfd
.get (), osection
, buf
, 0, len
))
161 warning (_("writing dump file '%s' (%s)"), filename
,
162 bfd_errmsg (bfd_get_error ()));
166 dump_memory_to_file (const char *cmd
, const char *mode
, const char *file_format
)
174 gdb::unique_xmalloc_ptr
<char> filename
= scan_filename (&cmd
, NULL
);
176 /* Find the low address. */
177 if (cmd
== NULL
|| *cmd
== '\0')
178 error (_("Missing start address."));
179 gdb::unique_xmalloc_ptr
<char> lo_exp
= scan_expression (&cmd
, NULL
);
181 /* Find the second address - rest of line. */
182 if (cmd
== NULL
|| *cmd
== '\0')
183 error (_("Missing stop address."));
186 lo
= parse_and_eval_address (lo_exp
.get ());
187 hi
= parse_and_eval_address (hi_exp
);
189 error (_("Invalid memory address range (start >= end)."));
192 /* FIXME: Should use read_memory_partial() and a magic blocking
194 gdb::byte_vector
buf (count
);
195 read_memory (lo
, buf
.data (), count
);
197 /* Have everything. Open/write the data. */
198 if (file_format
== NULL
|| strcmp (file_format
, "binary") == 0)
199 dump_binary_file (filename
.get (), mode
, buf
.data (), count
);
201 dump_bfd_file (filename
.get (), mode
, file_format
, lo
, buf
.data (), count
);
205 dump_memory_command (const char *cmd
, const char *mode
)
207 dump_memory_to_file (cmd
, mode
, "binary");
211 dump_value_to_file (const char *cmd
, const char *mode
, const char *file_format
)
216 gdb::unique_xmalloc_ptr
<char> filename
= scan_filename (&cmd
, NULL
);
218 /* Find the value. */
219 if (cmd
== NULL
|| *cmd
== '\0')
220 error (_("No value to %s."), *mode
== 'a' ? "append" : "dump");
221 val
= parse_and_eval (cmd
);
223 error (_("Invalid expression."));
225 /* Have everything. Open/write the data. */
226 if (file_format
== NULL
|| strcmp (file_format
, "binary") == 0)
227 dump_binary_file (filename
.get (), mode
, value_contents (val
).data (),
228 TYPE_LENGTH (value_type (val
)));
233 if (VALUE_LVAL (val
))
235 vaddr
= value_address (val
);
240 warning (_("value is not an lval: address assumed to be zero"));
243 dump_bfd_file (filename
.get (), mode
, file_format
, vaddr
,
244 value_contents (val
).data (),
245 TYPE_LENGTH (value_type (val
)));
250 dump_value_command (const char *cmd
, const char *mode
)
252 dump_value_to_file (cmd
, mode
, "binary");
256 dump_srec_memory (const char *args
, int from_tty
)
258 dump_memory_to_file (args
, FOPEN_WB
, "srec");
262 dump_srec_value (const char *args
, int from_tty
)
264 dump_value_to_file (args
, FOPEN_WB
, "srec");
268 dump_ihex_memory (const char *args
, int from_tty
)
270 dump_memory_to_file (args
, FOPEN_WB
, "ihex");
274 dump_ihex_value (const char *args
, int from_tty
)
276 dump_value_to_file (args
, FOPEN_WB
, "ihex");
280 dump_verilog_memory (const char *args
, int from_tty
)
282 dump_memory_to_file (args
, FOPEN_WB
, "verilog");
286 dump_verilog_value (const char *args
, int from_tty
)
288 dump_value_to_file (args
, FOPEN_WB
, "verilog");
292 dump_tekhex_memory (const char *args
, int from_tty
)
294 dump_memory_to_file (args
, FOPEN_WB
, "tekhex");
298 dump_tekhex_value (const char *args
, int from_tty
)
300 dump_value_to_file (args
, FOPEN_WB
, "tekhex");
304 dump_binary_memory (const char *args
, int from_tty
)
306 dump_memory_to_file (args
, FOPEN_WB
, "binary");
310 dump_binary_value (const char *args
, int from_tty
)
312 dump_value_to_file (args
, FOPEN_WB
, "binary");
316 append_binary_memory (const char *args
, int from_tty
)
318 dump_memory_to_file (args
, FOPEN_AB
, "binary");
322 append_binary_value (const char *args
, int from_tty
)
324 dump_value_to_file (args
, FOPEN_AB
, "binary");
329 void (*func
) (const char *cmd
, const char *mode
);
334 call_dump_func (const char *args
, int from_tty
, cmd_list_element
*c
)
336 struct dump_context
*d
= (struct dump_context
*) c
->context ();
338 d
->func (args
, d
->mode
);
342 add_dump_command (const char *name
,
343 void (*func
) (const char *args
, const char *mode
),
347 struct cmd_list_element
*c
;
348 struct dump_context
*d
;
350 c
= add_cmd (name
, all_commands
, descr
, &dump_cmdlist
);
351 c
->completer
= filename_completer
;
352 d
= XNEW (struct dump_context
);
356 c
->func
= call_dump_func
;
358 c
= add_cmd (name
, all_commands
, descr
, &append_cmdlist
);
359 c
->completer
= filename_completer
;
360 d
= XNEW (struct dump_context
);
364 c
->func
= call_dump_func
;
366 /* Replace "Dump " at start of docstring with "Append " (borrowed
367 from [deleted] deprecated_add_show_from_set). */
368 if ( c
->doc
[0] == 'W'
374 c
->doc
= concat ("Append ", c
->doc
+ 6, (char *)NULL
);
377 /* Selectively loads the sections into memory. */
380 restore_one_section (bfd
*ibfd
, asection
*isec
,
381 CORE_ADDR load_offset
,
382 CORE_ADDR load_start
,
385 bfd_vma sec_start
= bfd_section_vma (isec
);
386 bfd_size_type size
= bfd_section_size (isec
);
387 bfd_vma sec_end
= sec_start
+ size
;
388 bfd_size_type sec_offset
= 0;
389 bfd_size_type sec_load_count
= size
;
392 /* Ignore non-loadable sections, eg. from elf files. */
393 if (!(bfd_section_flags (isec
) & SEC_LOAD
))
396 /* Does the section overlap with the desired restore range? */
397 if (sec_end
<= load_start
398 || (load_end
> 0 && sec_start
>= load_end
))
400 /* No, no useable data in this section. */
401 gdb_printf (_("skipping section %s...\n"),
402 bfd_section_name (isec
));
406 /* Compare section address range with user-requested
407 address range (if any). Compute where the actual
408 transfer should start and end. */
409 if (sec_start
< load_start
)
410 sec_offset
= load_start
- sec_start
;
411 /* Size of a partial transfer. */
412 sec_load_count
-= sec_offset
;
413 if (load_end
> 0 && sec_end
> load_end
)
414 sec_load_count
-= sec_end
- load_end
;
417 gdb::byte_vector
buf (size
);
418 if (!bfd_get_section_contents (ibfd
, isec
, buf
.data (), 0, size
))
419 error (_("Failed to read bfd file %s: '%s'."), bfd_get_filename (ibfd
),
420 bfd_errmsg (bfd_get_error ()));
422 gdb_printf ("Restoring section %s (0x%lx to 0x%lx)",
423 bfd_section_name (isec
),
424 (unsigned long) sec_start
,
425 (unsigned long) sec_end
);
427 if (load_offset
!= 0 || load_start
!= 0 || load_end
!= 0)
428 gdb_printf (" into memory (%s to %s)\n",
429 paddress (target_gdbarch (),
430 (unsigned long) sec_start
431 + sec_offset
+ load_offset
),
432 paddress (target_gdbarch (),
433 (unsigned long) sec_start
+ sec_offset
434 + load_offset
+ sec_load_count
));
438 /* Write the data. */
439 ret
= target_write_memory (sec_start
+ sec_offset
+ load_offset
,
440 &buf
[sec_offset
], sec_load_count
);
442 warning (_("restore: memory write failed (%s)."), safe_strerror (ret
));
446 restore_binary_file (const char *filename
, CORE_ADDR load_offset
,
447 CORE_ADDR load_start
, CORE_ADDR load_end
)
450 gdb_file_up file
= gdb_fopen_cloexec (filename
, FOPEN_RB
);
454 error (_("Failed to open %s: %s"), filename
, safe_strerror (errno
));
456 /* Get the file size for reading. */
457 if (fseek (file
.get (), 0, SEEK_END
) == 0)
459 len
= ftell (file
.get ());
461 perror_with_name (filename
);
464 perror_with_name (filename
);
466 if (len
<= load_start
)
467 error (_("Start address is greater than length of binary file %s."),
470 /* Chop off "len" if it exceeds the requested load_end addr. */
471 if (load_end
!= 0 && load_end
< len
)
473 /* Chop off "len" if the requested load_start addr skips some bytes. */
478 ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
480 (unsigned long) (load_start
+ load_offset
),
481 (unsigned long) (load_start
+ load_offset
+ len
));
483 /* Now set the file pos to the requested load start pos. */
484 if (fseek (file
.get (), load_start
, SEEK_SET
) != 0)
485 perror_with_name (filename
);
487 /* Now allocate a buffer and read the file contents. */
488 gdb::byte_vector
buf (len
);
489 if (fread (buf
.data (), 1, len
, file
.get ()) != len
)
490 perror_with_name (filename
);
492 /* Now write the buffer into target memory. */
493 len
= target_write_memory (load_start
+ load_offset
, buf
.data (), len
);
495 warning (_("restore: memory write failed (%s)."), safe_strerror (len
));
499 restore_command (const char *args
, int from_tty
)
503 if (!target_has_execution ())
506 CORE_ADDR load_offset
= 0;
507 CORE_ADDR load_start
= 0;
508 CORE_ADDR load_end
= 0;
510 /* Parse the input arguments. First is filename (required). */
511 gdb::unique_xmalloc_ptr
<char> filename
= scan_filename (&args
, NULL
);
512 if (args
!= NULL
&& *args
!= '\0')
514 static const char binary_string
[] = "binary";
516 /* Look for optional "binary" flag. */
517 if (startswith (args
, binary_string
))
520 args
+= strlen (binary_string
);
521 args
= skip_spaces (args
);
523 /* Parse offset (optional). */
524 if (args
!= NULL
&& *args
!= '\0')
527 ? parse_and_eval_address (scan_expression (&args
, NULL
).get ())
528 : parse_and_eval_long (scan_expression (&args
, NULL
).get ()));
529 if (args
!= NULL
&& *args
!= '\0')
531 /* Parse start address (optional). */
533 parse_and_eval_long (scan_expression (&args
, NULL
).get ());
534 if (args
!= NULL
&& *args
!= '\0')
536 /* Parse end address (optional). */
537 load_end
= parse_and_eval_long (args
);
538 if (load_end
<= load_start
)
539 error (_("Start must be less than end."));
545 gdb_printf ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
546 filename
.get (), (unsigned long) load_offset
,
547 (unsigned long) load_start
,
548 (unsigned long) load_end
);
552 restore_binary_file (filename
.get (), load_offset
, load_start
,
557 /* Open the file for loading. */
558 gdb_bfd_ref_ptr
ibfd (bfd_openr_or_error (filename
.get (), NULL
));
560 /* Process the sections. */
561 for (asection
*sect
: gdb_bfd_sections (ibfd
))
562 restore_one_section (ibfd
.get (), sect
, load_offset
, load_start
,
567 void _initialize_cli_dump ();
569 _initialize_cli_dump ()
571 struct cmd_list_element
*c
;
573 add_basic_prefix_cmd ("dump", class_vars
,
574 _("Dump target code/data to a local file."),
578 add_basic_prefix_cmd ("append", class_vars
,
579 _("Append target code/data to a local file."),
584 add_dump_command ("memory", dump_memory_command
, "\
585 Write contents of memory to a raw binary file.\n\
586 Arguments are FILE START STOP. Writes the contents of memory within the\n\
587 range [START .. STOP) to the specified FILE in raw target ordered bytes.");
589 add_dump_command ("value", dump_value_command
, "\
590 Write the value of an expression to a raw binary file.\n\
591 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION to\n\
592 the specified FILE in raw target ordered bytes.");
594 add_basic_prefix_cmd ("srec", all_commands
,
595 _("Write target code/data to an srec file."),
600 add_basic_prefix_cmd ("ihex", all_commands
,
601 _("Write target code/data to an intel hex file."),
606 add_basic_prefix_cmd ("verilog", all_commands
,
607 _("Write target code/data to a verilog hex file."),
612 add_basic_prefix_cmd ("tekhex", all_commands
,
613 _("Write target code/data to a tekhex file."),
618 add_basic_prefix_cmd ("binary", all_commands
,
619 _("Write target code/data to a raw binary file."),
620 &binary_dump_cmdlist
,
624 add_basic_prefix_cmd ("binary", all_commands
,
625 _("Append target code/data to a raw binary file."),
626 &binary_append_cmdlist
,
630 add_cmd ("memory", all_commands
, dump_srec_memory
, _("\
631 Write contents of memory to an srec file.\n\
632 Arguments are FILE START STOP. Writes the contents of memory\n\
633 within the range [START .. STOP) to the specified FILE in srec format."),
636 add_cmd ("value", all_commands
, dump_srec_value
, _("\
637 Write the value of an expression to an srec file.\n\
638 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
639 to the specified FILE in srec format."),
642 add_cmd ("memory", all_commands
, dump_ihex_memory
, _("\
643 Write contents of memory to an ihex file.\n\
644 Arguments are FILE START STOP. Writes the contents of memory within\n\
645 the range [START .. STOP) to the specified FILE in intel hex format."),
648 add_cmd ("value", all_commands
, dump_ihex_value
, _("\
649 Write the value of an expression to an ihex file.\n\
650 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
651 to the specified FILE in intel hex format."),
654 add_cmd ("memory", all_commands
, dump_verilog_memory
, _("\
655 Write contents of memory to a verilog hex file.\n\
656 Arguments are FILE START STOP. Writes the contents of memory within\n\
657 the range [START .. STOP) to the specified FILE in verilog hex format."),
660 add_cmd ("value", all_commands
, dump_verilog_value
, _("\
661 Write the value of an expression to a verilog hex file.\n\
662 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
663 to the specified FILE in verilog hex format."),
666 add_cmd ("memory", all_commands
, dump_tekhex_memory
, _("\
667 Write contents of memory to a tekhex file.\n\
668 Arguments are FILE START STOP. Writes the contents of memory\n\
669 within the range [START .. STOP) to the specified FILE in tekhex format."),
672 add_cmd ("value", all_commands
, dump_tekhex_value
, _("\
673 Write the value of an expression to a tekhex file.\n\
674 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
675 to the specified FILE in tekhex format."),
678 add_cmd ("memory", all_commands
, dump_binary_memory
, _("\
679 Write contents of memory to a raw binary file.\n\
680 Arguments are FILE START STOP. Writes the contents of memory\n\
681 within the range [START .. STOP) to the specified FILE in binary format."),
682 &binary_dump_cmdlist
);
684 add_cmd ("value", all_commands
, dump_binary_value
, _("\
685 Write the value of an expression to a raw binary file.\n\
686 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
687 to the specified FILE in raw target ordered bytes."),
688 &binary_dump_cmdlist
);
690 add_cmd ("memory", all_commands
, append_binary_memory
, _("\
691 Append contents of memory to a raw binary file.\n\
692 Arguments are FILE START STOP. Writes the contents of memory within the\n\
693 range [START .. STOP) to the specified FILE in raw target ordered bytes."),
694 &binary_append_cmdlist
);
696 add_cmd ("value", all_commands
, append_binary_value
, _("\
697 Append the value of an expression to a raw binary file.\n\
698 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
699 to the specified FILE in raw target ordered bytes."),
700 &binary_append_cmdlist
);
702 c
= add_com ("restore", class_vars
, restore_command
, _("\
703 Restore the contents of FILE to target memory.\n\
704 Arguments are FILE OFFSET START END where all except FILE are optional.\n\
705 OFFSET will be added to the base address of the file (default zero).\n\
706 If START and END are given, only the file contents within that range\n\
707 (file relative) will be restored to target memory."));
708 c
->completer
= filename_completer
;
709 /* FIXME: completers for other commands. */