xref: /openbsd-src/gnu/usr.bin/binutils/gdb/cli/cli-dump.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
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