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