1 /* Dump-to-file commands, for GDB, the GNU debugger.
3 Copyright (C) 2002-2024 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"
38 static gdb::unique_xmalloc_ptr
<char>
39 scan_expression (const char **cmd
, const char *def
)
41 if ((*cmd
) == NULL
|| (**cmd
) == '\0')
42 return make_unique_xstrdup (def
);
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
);
56 static gdb::unique_xmalloc_ptr
<char>
57 scan_filename (const char **cmd
, const char *defname
)
59 gdb::unique_xmalloc_ptr
<char> filename
;
61 /* FIXME: Need to get the ``/a(ppend)'' flag from somewhere. */
67 error (_("Missing filename."));
68 filename
.reset (xstrdup (defname
));
72 /* FIXME: should parse a possibly quoted string. */
75 (*cmd
) = skip_spaces (*cmd
);
76 end
= *cmd
+ strcspn (*cmd
, " \t");
77 filename
.reset (savestring ((*cmd
), end
- (*cmd
)));
78 (*cmd
) = skip_spaces (end
);
80 gdb_assert (filename
!= NULL
);
82 return gdb::unique_xmalloc_ptr
<char> (tilde_expand (filename
.get ()));
85 static gdb_bfd_ref_ptr
86 bfd_openr_or_error (const char *filename
, const char *target
)
88 gdb_bfd_ref_ptr
ibfd (gdb_bfd_openr (filename
, target
));
90 error (_("Failed to open %s: %s."), filename
,
91 bfd_errmsg (bfd_get_error ()));
93 if (!bfd_check_format (ibfd
.get (), bfd_object
))
94 error (_("'%s' is not a recognized file format."), filename
);
99 static gdb_bfd_ref_ptr
100 bfd_openw_or_error (const char *filename
, const char *target
, const char *mode
)
102 gdb_bfd_ref_ptr obfd
;
104 if (*mode
== 'w') /* Write: create new file */
106 obfd
= gdb_bfd_openw (filename
, target
);
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 ()));
113 else if (*mode
== 'a') /* Append to existing file. */
114 { /* FIXME -- doesn't work... */
115 error (_("bfd_openw does not work with append."));
118 error (_("bfd_openw_or_error: unknown mode %s."), mode
);
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
;
133 dump_binary_file (const char *filename
, const char *mode
,
134 const bfd_byte
*buf
, ULONGEST len
)
138 gdb_file_up file
= gdb_fopen_cloexec (filename
, mode
);
140 perror_with_name (filename
);
142 status
= fwrite (buf
, len
, 1, file
.get ());
144 perror_with_name (filename
);
148 dump_bfd_file (const char *filename
, const char *mode
,
149 const char *target
, CORE_ADDR vaddr
,
150 const bfd_byte
*buf
, ULONGEST len
)
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 ()));
167 dump_memory_to_file (const char *cmd
, const char *mode
, const char *file_format
)
175 gdb::unique_xmalloc_ptr
<char> filename
= scan_filename (&cmd
, NULL
);
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
);
182 /* Find the second address - rest of line. */
183 if (cmd
== NULL
|| *cmd
== '\0')
184 error (_("Missing stop address."));
187 lo
= parse_and_eval_address (lo_exp
.get ());
188 hi
= parse_and_eval_address (hi_exp
);
190 error (_("Invalid memory address range (start >= end)."));
193 /* FIXME: Should use read_memory_partial() and a magic blocking
195 gdb::byte_vector
buf (count
);
196 read_memory (lo
, buf
.data (), count
);
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
);
202 dump_bfd_file (filename
.get (), mode
, file_format
, lo
, buf
.data (), count
);
206 dump_memory_command (const char *cmd
, const char *mode
)
208 dump_memory_to_file (cmd
, mode
, "binary");
212 dump_value_to_file (const char *cmd
, const char *mode
, const char *file_format
)
217 gdb::unique_xmalloc_ptr
<char> filename
= scan_filename (&cmd
, NULL
);
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
);
224 error (_("Invalid expression."));
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 ());
236 vaddr
= val
->address ();
241 warning (_("value is not an lval: address assumed to be zero"));
244 dump_bfd_file (filename
.get (), mode
, file_format
, vaddr
,
245 val
->contents ().data (),
246 val
->type ()->length ());
251 dump_value_command (const char *cmd
, const char *mode
)
253 dump_value_to_file (cmd
, mode
, "binary");
257 dump_srec_memory (const char *args
, int from_tty
)
259 dump_memory_to_file (args
, FOPEN_WB
, "srec");
263 dump_srec_value (const char *args
, int from_tty
)
265 dump_value_to_file (args
, FOPEN_WB
, "srec");
269 dump_ihex_memory (const char *args
, int from_tty
)
271 dump_memory_to_file (args
, FOPEN_WB
, "ihex");
275 dump_ihex_value (const char *args
, int from_tty
)
277 dump_value_to_file (args
, FOPEN_WB
, "ihex");
281 dump_verilog_memory (const char *args
, int from_tty
)
283 dump_memory_to_file (args
, FOPEN_WB
, "verilog");
287 dump_verilog_value (const char *args
, int from_tty
)
289 dump_value_to_file (args
, FOPEN_WB
, "verilog");
293 dump_tekhex_memory (const char *args
, int from_tty
)
295 dump_memory_to_file (args
, FOPEN_WB
, "tekhex");
299 dump_tekhex_value (const char *args
, int from_tty
)
301 dump_value_to_file (args
, FOPEN_WB
, "tekhex");
305 dump_binary_memory (const char *args
, int from_tty
)
307 dump_memory_to_file (args
, FOPEN_WB
, "binary");
311 dump_binary_value (const char *args
, int from_tty
)
313 dump_value_to_file (args
, FOPEN_WB
, "binary");
317 append_binary_memory (const char *args
, int from_tty
)
319 dump_memory_to_file (args
, FOPEN_AB
, "binary");
323 append_binary_value (const char *args
, int from_tty
)
325 dump_value_to_file (args
, FOPEN_AB
, "binary");
330 void (*func
) (const char *cmd
, const char *mode
);
335 call_dump_func (const char *args
, int from_tty
, cmd_list_element
*c
)
337 struct dump_context
*d
= (struct dump_context
*) c
->context ();
339 d
->func (args
, d
->mode
);
343 add_dump_command (const char *name
,
344 void (*func
) (const char *args
, const char *mode
),
348 struct cmd_list_element
*c
;
349 struct dump_context
*d
;
351 c
= add_cmd (name
, all_commands
, descr
, &dump_cmdlist
);
352 c
->completer
= filename_completer
;
353 d
= XNEW (struct dump_context
);
357 c
->func
= call_dump_func
;
359 c
= add_cmd (name
, all_commands
, descr
, &append_cmdlist
);
360 c
->completer
= filename_completer
;
361 d
= XNEW (struct dump_context
);
365 c
->func
= call_dump_func
;
367 /* Replace "Dump " at start of docstring with "Append " (borrowed
368 from [deleted] deprecated_add_show_from_set). */
369 if ( c
->doc
[0] == 'W'
375 c
->doc
= concat ("Append ", c
->doc
+ 6, (char *)NULL
);
378 /* Selectively loads the sections into memory. */
381 restore_one_section (bfd
*ibfd
, asection
*isec
,
382 CORE_ADDR load_offset
,
383 CORE_ADDR load_start
,
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
;
393 /* Ignore non-loadable sections, eg. from elf files. */
394 if (!(bfd_section_flags (isec
) & SEC_LOAD
))
397 /* Does the section overlap with the desired restore range? */
398 if (sec_end
<= load_start
399 || (load_end
> 0 && sec_start
>= load_end
))
401 /* No, no useable data in this section. */
402 gdb_printf (_("skipping section %s...\n"),
403 bfd_section_name (isec
));
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
;
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 ()));
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
);
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
));
439 /* Write the data. */
440 ret
= target_write_memory (sec_start
+ sec_offset
+ load_offset
,
441 &buf
[sec_offset
], sec_load_count
);
443 warning (_("restore: memory write failed (%s)."), safe_strerror (ret
));
447 restore_binary_file (const char *filename
, CORE_ADDR load_offset
,
448 CORE_ADDR load_start
, CORE_ADDR load_end
)
451 gdb_file_up file
= gdb_fopen_cloexec (filename
, FOPEN_RB
);
455 error (_("Failed to open %s: %s"), filename
, safe_strerror (errno
));
457 /* Get the file size for reading. */
458 if (fseek (file
.get (), 0, SEEK_END
) == 0)
460 len
= ftell (file
.get ());
462 perror_with_name (filename
);
465 perror_with_name (filename
);
467 if (len
<= load_start
)
468 error (_("Start address is greater than length of binary file %s."),
471 /* Chop off "len" if it exceeds the requested load_end addr. */
472 if (load_end
!= 0 && load_end
< len
)
474 /* Chop off "len" if the requested load_start addr skips some bytes. */
479 ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
481 (unsigned long) (load_start
+ load_offset
),
482 (unsigned long) (load_start
+ load_offset
+ len
));
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
);
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
);
493 /* Now write the buffer into target memory. */
494 len
= target_write_memory (load_start
+ load_offset
, buf
.data (), len
);
496 warning (_("restore: memory write failed (%s)."), safe_strerror (len
));
500 restore_command (const char *args
, int from_tty
)
504 if (!target_has_execution ())
507 CORE_ADDR load_offset
= 0;
508 CORE_ADDR load_start
= 0;
509 CORE_ADDR load_end
= 0;
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')
515 static const char binary_string
[] = "binary";
517 /* Look for optional "binary" flag. */
518 if (startswith (args
, binary_string
))
521 args
+= strlen (binary_string
);
522 args
= skip_spaces (args
);
524 /* Parse offset (optional). */
525 if (args
!= NULL
&& *args
!= '\0')
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')
532 /* Parse start address (optional). */
534 parse_and_eval_long (scan_expression (&args
, NULL
).get ());
535 if (args
!= NULL
&& *args
!= '\0')
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."));
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
);
553 restore_binary_file (filename
.get (), load_offset
, load_start
,
558 /* Open the file for loading. */
559 gdb_bfd_ref_ptr
ibfd (bfd_openr_or_error (filename
.get (), NULL
));
561 /* Process the sections. */
562 for (asection
*sect
: gdb_bfd_sections (ibfd
))
563 restore_one_section (ibfd
.get (), sect
, load_offset
, load_start
,
568 void _initialize_cli_dump ();
570 _initialize_cli_dump ()
572 struct cmd_list_element
*c
;
574 add_basic_prefix_cmd ("dump", class_vars
,
575 _("Dump target code/data to a local file."),
579 add_basic_prefix_cmd ("append", class_vars
,
580 _("Append target code/data to a local file."),
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.");
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.");
595 add_basic_prefix_cmd ("srec", all_commands
,
596 _("Write target code/data to an srec file."),
601 add_basic_prefix_cmd ("ihex", all_commands
,
602 _("Write target code/data to an intel hex file."),
607 add_basic_prefix_cmd ("verilog", all_commands
,
608 _("Write target code/data to a verilog hex file."),
613 add_basic_prefix_cmd ("tekhex", all_commands
,
614 _("Write target code/data to a tekhex file."),
619 add_basic_prefix_cmd ("binary", all_commands
,
620 _("Write target code/data to a raw binary file."),
621 &binary_dump_cmdlist
,
625 add_basic_prefix_cmd ("binary", all_commands
,
626 _("Append target code/data to a raw binary file."),
627 &binary_append_cmdlist
,
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."),
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."),
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."),
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."),
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."),
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."),
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."),
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."),
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
);
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
);
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
);
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
);
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. */