1 /* Dump-to-file commands, for GDB, the GNU debugger.
3 Copyright 2002 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 2 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, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
25 #include "gdb_string.h"
26 #include "cli/cli-decode.h"
27 #include "cli/cli-cmds.h"
29 #include "completer.h"
30 #include "cli/cli-dump.h"
31 #include "gdb_assert.h"
35 #define XMALLOC(TYPE) ((TYPE*) xmalloc (sizeof (TYPE)))
39 skip_spaces (char *chp
)
43 while (isspace (*chp
))
49 scan_expression_with_cleanup (char **cmd
, const char *def
)
51 if ((*cmd
) == NULL
|| (**cmd
) == '\0')
53 char *exp
= xstrdup (def
);
54 make_cleanup (xfree
, exp
);
62 end
= (*cmd
) + strcspn (*cmd
, " \t");
63 exp
= savestring ((*cmd
), end
- (*cmd
));
64 make_cleanup (xfree
, exp
);
65 (*cmd
) = skip_spaces (end
);
72 do_fclose_cleanup (void *arg
)
78 static struct cleanup
*
79 make_cleanup_fclose (FILE *file
)
81 return make_cleanup (do_fclose_cleanup
, file
);
85 scan_filename_with_cleanup (char **cmd
, const char *defname
)
90 /* FIXME: Need to get the ``/a(ppend)'' flag from somewhere. */
96 error ("Missing filename.");
97 filename
= xstrdup (defname
);
98 make_cleanup (xfree
, filename
);
102 /* FIXME: should parse a possibly quoted string. */
105 (*cmd
) = skip_spaces (*cmd
);
106 end
= *cmd
+ strcspn (*cmd
, " \t");
107 filename
= savestring ((*cmd
), end
- (*cmd
));
108 make_cleanup (xfree
, filename
);
109 (*cmd
) = skip_spaces (end
);
111 gdb_assert (filename
!= NULL
);
113 fullname
= tilde_expand (filename
);
114 make_cleanup (xfree
, fullname
);
120 fopen_with_cleanup (char *filename
, const char *mode
)
122 FILE *file
= fopen (filename
, mode
);
124 perror_with_name (filename
);
125 make_cleanup_fclose (file
);
130 bfd_openr_with_cleanup (const char *filename
, const char *target
)
134 if ((ibfd
= bfd_openr (filename
, target
)) == NULL
)
135 error ("Failed to open %s: %s.", filename
,
136 bfd_errmsg (bfd_get_error ()));
138 make_cleanup_bfd_close (ibfd
);
139 if (!bfd_check_format (ibfd
, bfd_object
))
140 error ("'%s' is not a recognized file format.", filename
);
146 bfd_openw_with_cleanup (char *filename
, const char *target
, char *mode
)
150 if (*mode
== 'w') /* Write: create new file */
152 if ((obfd
= bfd_openw (filename
, target
)) == NULL
)
153 error ("Failed to open %s: %s.", filename
,
154 bfd_errmsg (bfd_get_error ()));
155 make_cleanup_bfd_close (obfd
);
156 if (!bfd_set_format (obfd
, bfd_object
))
157 error ("bfd_openw_with_cleanup: %s.", bfd_errmsg (bfd_get_error ()));
159 else if (*mode
== 'a') /* Append to existing file */
160 { /* FIXME -- doesn't work... */
161 error ("bfd_openw does not work with append.");
164 error ("bfd_openw_with_cleanup: unknown mode %s.", mode
);
169 struct cmd_list_element
*dump_cmdlist
;
170 struct cmd_list_element
*append_cmdlist
;
171 struct cmd_list_element
*srec_cmdlist
;
172 struct cmd_list_element
*ihex_cmdlist
;
173 struct cmd_list_element
*tekhex_cmdlist
;
174 struct cmd_list_element
*binary_dump_cmdlist
;
175 struct cmd_list_element
*binary_append_cmdlist
;
178 dump_command (char *cmd
, int from_tty
)
180 printf_unfiltered ("\"dump\" must be followed by a subcommand.\n\n");
181 help_list (dump_cmdlist
, "dump ", -1, gdb_stdout
);
185 append_command (char *cmd
, int from_tty
)
187 printf_unfiltered ("\"append\" must be followed by a subcommand.\n\n");
188 help_list (dump_cmdlist
, "append ", -1, gdb_stdout
);
192 dump_binary_file (char *filename
, char *mode
,
198 file
= fopen_with_cleanup (filename
, mode
);
199 status
= fwrite (buf
, len
, 1, file
);
201 perror_with_name (filename
);
205 dump_bfd_file (char *filename
, char *mode
,
206 char *target
, CORE_ADDR vaddr
,
212 obfd
= bfd_openw_with_cleanup (filename
, target
, mode
);
213 osection
= bfd_make_section_anyway (obfd
, ".newsec");
214 bfd_set_section_size (obfd
, osection
, len
);
215 bfd_set_section_vma (obfd
, osection
, vaddr
);
216 bfd_set_section_alignment (obfd
, osection
, 0);
217 bfd_set_section_flags (obfd
, osection
, 0x203);
218 osection
->entsize
= 0;
219 bfd_set_section_contents (obfd
, osection
, buf
, 0, len
);
223 dump_memory_to_file (char *cmd
, char *mode
, char *file_format
)
225 struct cleanup
*old_cleanups
= make_cleanup (null_cleanup
, NULL
);
236 filename
= scan_filename_with_cleanup (&cmd
, NULL
);
238 /* Find the low address. */
239 if (cmd
== NULL
|| *cmd
== '\0')
240 error ("Missing start address.");
241 lo_exp
= scan_expression_with_cleanup (&cmd
, NULL
);
243 /* Find the second address - rest of line. */
244 if (cmd
== NULL
|| *cmd
== '\0')
245 error ("Missing stop address.");
248 lo
= parse_and_eval_address (lo_exp
);
249 hi
= parse_and_eval_address (hi_exp
);
251 error ("Invalid memory address range (start >= end).");
254 /* FIXME: Should use read_memory_partial() and a magic blocking
256 buf
= xmalloc (count
);
257 make_cleanup (xfree
, buf
);
258 target_read_memory (lo
, buf
, count
);
260 /* Have everything. Open/write the data. */
261 if (file_format
== NULL
|| strcmp (file_format
, "binary") == 0)
263 dump_binary_file (filename
, mode
, buf
, count
);
267 dump_bfd_file (filename
, mode
, file_format
, lo
, buf
, count
);
270 do_cleanups (old_cleanups
);
274 dump_memory_command (char *cmd
, char *mode
)
276 dump_memory_to_file (cmd
, mode
, "binary");
280 dump_value_to_file (char *cmd
, char *mode
, char *file_format
)
282 struct cleanup
*old_cleanups
= make_cleanup (null_cleanup
, NULL
);
287 filename
= scan_filename_with_cleanup (&cmd
, NULL
);
289 /* Find the value. */
290 if (cmd
== NULL
|| *cmd
== '\0')
291 error ("No value to %s.", *mode
== 'a' ? "append" : "dump");
292 val
= parse_and_eval (cmd
);
294 error ("Invalid expression.");
296 /* Have everything. Open/write the data. */
297 if (file_format
== NULL
|| strcmp (file_format
, "binary") == 0)
299 dump_binary_file (filename
, mode
, VALUE_CONTENTS (val
),
300 TYPE_LENGTH (VALUE_TYPE (val
)));
306 if (VALUE_LVAL (val
))
308 vaddr
= VALUE_ADDRESS (val
);
313 warning ("value is not an lval: address assumed to be zero");
316 dump_bfd_file (filename
, mode
, file_format
, vaddr
,
317 VALUE_CONTENTS (val
),
318 TYPE_LENGTH (VALUE_TYPE (val
)));
321 do_cleanups (old_cleanups
);
325 dump_value_command (char *cmd
, char *mode
)
327 dump_value_to_file (cmd
, mode
, "binary");
331 dump_filetype (char *cmd
, char *mode
, char *filetype
)
335 if (cmd
== NULL
|| *cmd
== '\0')
336 error ("Missing subcommand: try 'help %s %s'.",
337 mode
[0] == 'a' ? "append" : "dump",
340 suffix
+= strcspn (cmd
, " \t");
344 if (strncmp ("memory", cmd
, suffix
- cmd
) == 0)
346 dump_memory_to_file (suffix
, mode
, filetype
);
349 else if (strncmp ("value", cmd
, suffix
- cmd
) == 0)
351 dump_value_to_file (suffix
, mode
, filetype
);
356 error ("dump %s: unknown subcommand '%s' -- try 'value' or 'memory'.",
361 dump_srec_memory (char *args
, int from_tty
)
363 dump_memory_to_file (args
, "w", "srec");
367 dump_srec_value (char *args
, int from_tty
)
369 dump_value_to_file (args
, "w", "srec");
373 dump_ihex_memory (char *args
, int from_tty
)
375 dump_memory_to_file (args
, "w", "ihex");
379 dump_ihex_value (char *args
, int from_tty
)
381 dump_value_to_file (args
, "w", "ihex");
385 dump_tekhex_memory (char *args
, int from_tty
)
387 dump_memory_to_file (args
, "w", "tekhex");
391 dump_tekhex_value (char *args
, int from_tty
)
393 dump_value_to_file (args
, "w", "tekhex");
397 dump_binary_memory (char *args
, int from_tty
)
399 dump_memory_to_file (args
, "w", "binary");
403 dump_binary_value (char *args
, int from_tty
)
405 dump_value_to_file (args
, "w", "binary");
409 append_binary_memory (char *args
, int from_tty
)
411 dump_memory_to_file (args
, "a", "binary");
415 append_binary_value (char *args
, int from_tty
)
417 dump_value_to_file (args
, "a", "binary");
422 void (*func
) (char *cmd
, char *mode
);
427 call_dump_func (struct cmd_list_element
*c
, char *args
, int from_tty
)
429 struct dump_context
*d
= get_cmd_context (c
);
430 d
->func (args
, d
->mode
);
434 add_dump_command (char *name
, void (*func
) (char *args
, char *mode
),
438 struct cmd_list_element
*c
;
439 struct dump_context
*d
;
441 c
= add_cmd (name
, all_commands
, NULL
, descr
, &dump_cmdlist
);
442 c
->completer
= filename_completer
;
443 d
= XMALLOC (struct dump_context
);
446 set_cmd_context (c
, d
);
447 c
->func
= call_dump_func
;
449 c
= add_cmd (name
, all_commands
, NULL
, descr
, &append_cmdlist
);
450 c
->completer
= filename_completer
;
451 d
= XMALLOC (struct dump_context
);
454 set_cmd_context (c
, d
);
455 c
->func
= call_dump_func
;
457 /* Replace "Dump " at start of docstring with "Append "
458 (borrowed from add_show_from_set). */
459 if ( c
->doc
[0] == 'W'
465 c
->doc
= concat ("Append ", c
->doc
+ 6, NULL
);
468 /* Opaque data for restore_section_callback. */
469 struct callback_data
{
470 unsigned long load_offset
;
471 CORE_ADDR load_start
;
475 /* Function: restore_section_callback.
477 Callback function for bfd_map_over_sections.
478 Selectively loads the sections into memory. */
481 restore_section_callback (bfd
*ibfd
, asection
*isec
, void *args
)
483 struct callback_data
*data
= args
;
484 bfd_vma sec_start
= bfd_section_vma (ibfd
, isec
);
485 bfd_size_type size
= bfd_section_size (ibfd
, isec
);
486 bfd_vma sec_end
= sec_start
+ size
;
487 bfd_size_type sec_offset
= 0;
488 bfd_size_type sec_load_count
= size
;
489 struct cleanup
*old_chain
;
493 /* Ignore non-loadable sections, eg. from elf files. */
494 if (!(bfd_get_section_flags (ibfd
, isec
) & SEC_LOAD
))
497 /* Does the section overlap with the desired restore range? */
498 if (sec_end
<= data
->load_start
499 || (data
->load_end
> 0 && sec_start
>= data
->load_end
))
501 /* No, no useable data in this section. */
502 printf_filtered ("skipping section %s...\n",
503 bfd_section_name (ibfd
, isec
));
507 /* Compare section address range with user-requested
508 address range (if any). Compute where the actual
509 transfer should start and end. */
510 if (sec_start
< data
->load_start
)
511 sec_offset
= data
->load_start
- sec_start
;
512 /* Size of a partial transfer: */
513 sec_load_count
-= sec_offset
;
514 if (data
->load_end
> 0 && sec_end
> data
->load_end
)
515 sec_load_count
-= sec_end
- data
->load_end
;
518 buf
= xmalloc (size
);
519 old_chain
= make_cleanup (xfree
, buf
);
520 if (!bfd_get_section_contents (ibfd
, isec
, buf
, 0, size
))
521 error ("Failed to read bfd file %s: '%s'.", bfd_get_filename (ibfd
),
522 bfd_errmsg (bfd_get_error ()));
524 printf_filtered ("Restoring section %s (0x%lx to 0x%lx)",
525 bfd_section_name (ibfd
, isec
),
526 (unsigned long) sec_start
,
527 (unsigned long) sec_end
);
529 if (data
->load_offset
!= 0 || data
->load_start
!= 0 || data
->load_end
!= 0)
530 printf_filtered (" into memory (0x%s to 0x%s)\n",
531 paddr_nz ((unsigned long) sec_start
532 + sec_offset
+ data
->load_offset
),
533 paddr_nz ((unsigned long) sec_start
+ sec_offset
534 + data
->load_offset
+ sec_load_count
));
536 puts_filtered ("\n");
538 /* Write the data. */
539 ret
= target_write_memory (sec_start
+ sec_offset
+ data
->load_offset
,
540 buf
+ sec_offset
, sec_load_count
);
542 warning ("restore: memory write failed (%s).", safe_strerror (ret
));
543 do_cleanups (old_chain
);
548 restore_binary_file (char *filename
, struct callback_data
*data
)
550 FILE *file
= fopen_with_cleanup (filename
, "r");
555 /* Get the file size for reading. */
556 if (fseek (file
, 0, SEEK_END
) == 0)
559 perror_with_name (filename
);
561 if (len
<= data
->load_start
)
562 error ("Start address is greater than length of binary file %s.",
565 /* Chop off "len" if it exceeds the requested load_end addr. */
566 if (data
->load_end
!= 0 && data
->load_end
< len
)
567 len
= data
->load_end
;
568 /* Chop off "len" if the requested load_start addr skips some bytes. */
569 if (data
->load_start
> 0)
570 len
-= data
->load_start
;
573 ("Restoring binary file %s into memory (0x%lx to 0x%lx)\n",
575 (unsigned long) data
->load_start
+ data
->load_offset
,
576 (unsigned long) data
->load_start
+ data
->load_offset
+ len
);
578 /* Now set the file pos to the requested load start pos. */
579 if (fseek (file
, data
->load_start
, SEEK_SET
) != 0)
580 perror_with_name (filename
);
582 /* Now allocate a buffer and read the file contents. */
584 make_cleanup (xfree
, buf
);
585 if (fread (buf
, 1, len
, file
) != len
)
586 perror_with_name (filename
);
588 /* Now write the buffer into target memory. */
589 len
= target_write_memory (data
->load_start
+ data
->load_offset
, buf
, len
);
591 warning ("restore: memory write failed (%s).", safe_strerror (len
));
596 restore_command (char *args
, int from_tty
)
599 struct callback_data data
;
603 if (!target_has_execution
)
606 data
.load_offset
= 0;
610 /* Parse the input arguments. First is filename (required). */
611 filename
= scan_filename_with_cleanup (&args
, NULL
);
612 if (args
!= NULL
&& *args
!= '\0')
614 char *binary_string
= "binary";
616 /* Look for optional "binary" flag. */
617 if (strncmp (args
, binary_string
, strlen (binary_string
)) == 0)
620 args
+= strlen (binary_string
);
621 args
= skip_spaces (args
);
623 /* Parse offset (optional). */
624 if (args
!= NULL
&& *args
!= '\0')
626 parse_and_eval_address (scan_expression_with_cleanup (&args
,
628 if (args
!= NULL
&& *args
!= '\0')
630 /* Parse start address (optional). */
632 parse_and_eval_address (scan_expression_with_cleanup (&args
,
634 if (args
!= NULL
&& *args
!= '\0')
636 /* Parse end address (optional). */
637 data
.load_end
= parse_and_eval_address (args
);
638 if (data
.load_end
<= data
.load_start
)
639 error ("Start must be less than end.");
645 printf_filtered ("Restore file %s offset 0x%lx start 0x%lx end 0x%lx\n",
646 filename
, (unsigned long) data
.load_offset
,
647 (unsigned long) data
.load_start
,
648 (unsigned long) data
.load_end
);
652 restore_binary_file (filename
, &data
);
656 /* Open the file for loading. */
657 ibfd
= bfd_openr_with_cleanup (filename
, NULL
);
659 /* Process the sections. */
660 bfd_map_over_sections (ibfd
, restore_section_callback
, &data
);
666 srec_dump_command (char *cmd
, int from_tty
)
668 printf_unfiltered ("\"dump srec\" must be followed by a subcommand.\n");
669 help_list (srec_cmdlist
, "dump srec ", -1, gdb_stdout
);
673 ihex_dump_command (char *cmd
, int from_tty
)
675 printf_unfiltered ("\"dump ihex\" must be followed by a subcommand.\n");
676 help_list (ihex_cmdlist
, "dump ihex ", -1, gdb_stdout
);
680 tekhex_dump_command (char *cmd
, int from_tty
)
682 printf_unfiltered ("\"dump tekhex\" must be followed by a subcommand.\n");
683 help_list (tekhex_cmdlist
, "dump tekhex ", -1, gdb_stdout
);
687 binary_dump_command (char *cmd
, int from_tty
)
689 printf_unfiltered ("\"dump binary\" must be followed by a subcommand.\n");
690 help_list (binary_dump_cmdlist
, "dump binary ", -1, gdb_stdout
);
694 binary_append_command (char *cmd
, int from_tty
)
696 printf_unfiltered ("\"append binary\" must be followed by a subcommand.\n");
697 help_list (binary_append_cmdlist
, "append binary ", -1, gdb_stdout
);
701 _initialize_cli_dump (void)
703 struct cmd_list_element
*c
;
704 add_prefix_cmd ("dump", class_vars
, dump_command
, "\
705 Dump target code/data to a local file.",
706 &dump_cmdlist
, "dump ",
709 add_prefix_cmd ("append", class_vars
, append_command
, "\
710 Append target code/data to a local file.",
711 &append_cmdlist
, "append ",
715 add_dump_command ("memory", dump_memory_command
, "\
716 Write contents of memory to a raw binary file.\n\
717 Arguments are FILE START STOP. Writes the contents of memory within the\n\
718 range [START .. STOP) to the specifed FILE in raw target ordered bytes.");
720 add_dump_command ("value", dump_value_command
, "\
721 Write the value of an expression to a raw binary file.\n\
722 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION to\n\
723 the specified FILE in raw target ordered bytes.");
725 add_prefix_cmd ("srec", all_commands
, srec_dump_command
, "\
726 Write target code/data to an srec file.",
727 &srec_cmdlist
, "dump srec ",
731 add_prefix_cmd ("ihex", all_commands
, ihex_dump_command
, "\
732 Write target code/data to an intel hex file.",
733 &ihex_cmdlist
, "dump ihex ",
737 add_prefix_cmd ("tekhex", all_commands
, tekhex_dump_command
, "\
738 Write target code/data to a tekhex file.",
739 &tekhex_cmdlist
, "dump tekhex ",
743 add_prefix_cmd ("binary", all_commands
, binary_dump_command
, "\
744 Write target code/data to a raw binary file.",
745 &binary_dump_cmdlist
, "dump binary ",
749 add_prefix_cmd ("binary", all_commands
, binary_append_command
, "\
750 Append target code/data to a raw binary file.",
751 &binary_append_cmdlist
, "append binary ",
755 add_cmd ("memory", all_commands
, dump_srec_memory
, "\
756 Write contents of memory to an srec file.\n\
757 Arguments are FILE START STOP. Writes the contents of memory\n\
758 within the range [START .. STOP) to the specifed FILE in srec format.",
761 add_cmd ("value", all_commands
, dump_srec_value
, "\
762 Write the value of an expression to an srec file.\n\
763 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
764 to the specified FILE in srec format.",
767 add_cmd ("memory", all_commands
, dump_ihex_memory
, "\
768 Write contents of memory to an ihex file.\n\
769 Arguments are FILE START STOP. Writes the contents of memory within\n\
770 the range [START .. STOP) to the specifed FILE in intel hex format.",
773 add_cmd ("value", all_commands
, dump_ihex_value
, "\
774 Write the value of an expression to an ihex file.\n\
775 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
776 to the specified FILE in intel hex format.",
779 add_cmd ("memory", all_commands
, dump_tekhex_memory
, "\
780 Write contents of memory to a tekhex file.\n\
781 Arguments are FILE START STOP. Writes the contents of memory\n\
782 within the range [START .. STOP) to the specifed FILE in tekhex format.",
785 add_cmd ("value", all_commands
, dump_tekhex_value
, "\
786 Write the value of an expression to a tekhex file.\n\
787 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
788 to the specified FILE in tekhex format.",
791 add_cmd ("memory", all_commands
, dump_binary_memory
, "\
792 Write contents of memory to a raw binary file.\n\
793 Arguments are FILE START STOP. Writes the contents of memory\n\
794 within the range [START .. STOP) to the specifed FILE in binary format.",
795 &binary_dump_cmdlist
);
797 add_cmd ("value", all_commands
, dump_binary_value
, "\
798 Write the value of an expression to a raw binary file.\n\
799 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
800 to the specified FILE in raw target ordered bytes.",
801 &binary_dump_cmdlist
);
803 add_cmd ("memory", all_commands
, append_binary_memory
, "\
804 Append contents of memory to a raw binary file.\n\
805 Arguments are FILE START STOP. Writes the contents of memory within the\n\
806 range [START .. STOP) to the specifed FILE in raw target ordered bytes.",
807 &binary_append_cmdlist
);
809 add_cmd ("value", all_commands
, append_binary_value
, "\
810 Append the value of an expression to a raw binary file.\n\
811 Arguments are FILE EXPRESSION. Writes the value of EXPRESSION\n\
812 to the specified FILE in raw target ordered bytes.",
813 &binary_append_cmdlist
);
815 c
= add_com ("restore", class_vars
, restore_command
,
816 "Restore the contents of FILE to target memory.\n\
817 Arguments are FILE OFFSET START END where all except FILE are optional.\n\
818 OFFSET will be added to the base address of the file (default zero).\n\
819 If START and END are given, only the file contents within that range\n\
820 (file relative) will be restored to target memory.");
821 c
->completer
= filename_completer
;
822 /* FIXME: completers for other commands. */