c9bbd01ef533ecca705e2596b3b37717c422bb76
[external/binutils.git] / sim / common / sim-load.c
1 /* Utility to load a file into the simulator.
2    Copyright (C) 1997, 1998, 2001, 2002, 2004, 2007
3    Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation, Inc.,
17 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19 /* This is a standalone loader, independent of the sim-basic.h machinery,
20    as it is used by simulators that don't use it [though that doesn't mean
21    to suggest that they shouldn't :-)].  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "cconfig.h"
25 #endif
26 #include "ansidecl.h"
27 #include <stdio.h> /* for NULL */
28 #include <stdarg.h>
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #include <time.h>
33
34 #include "sim-basics.h"
35 #include "bfd.h"
36 #include "sim-utils.h"
37
38 #include "gdb/callback.h"
39 #include "gdb/remote-sim.h"
40
41 static void eprintf PARAMS ((host_callback *, const char *, ...));
42 static void xprintf PARAMS ((host_callback *, const char *, ...));
43 static void report_transfer_performance
44   PARAMS ((host_callback *, unsigned long, time_t, time_t));
45 static void xprintf_bfd_vma PARAMS ((host_callback *, bfd_vma));
46
47 /* Load program PROG into the simulator using the function DO_LOAD.
48    If PROG_BFD is non-NULL, the file has already been opened.
49    If VERBOSE_P is non-zero statistics are printed of each loaded section
50    and the transfer rate (for consistency with gdb).
51    If LMA_P is non-zero the program sections are loaded at the LMA
52    rather than the VMA
53    If this fails an error message is printed and NULL is returned.
54    If it succeeds the bfd is returned.
55    NOTE: For historical reasons, older hardware simulators incorrectly
56    write the program sections at LMA interpreted as a virtual address.
57    This is still accommodated for backward compatibility reasons. */
58
59
60 bfd *
61 sim_load_file (sd, myname, callback, prog, prog_bfd, verbose_p, lma_p, do_write)
62      SIM_DESC sd;
63      const char *myname;
64      host_callback *callback;
65      char *prog;
66      bfd *prog_bfd;
67      int verbose_p;
68      int lma_p;
69      sim_write_fn do_write;
70 {
71   asection *s;
72   /* Record separately as we don't want to close PROG_BFD if it was passed.  */
73   bfd *result_bfd;
74   time_t start_time = 0;        /* Start and end times of download */
75   time_t end_time = 0;
76   unsigned long data_count = 0; /* Number of bytes transferred to memory */
77   int found_loadable_section;
78
79   if (prog_bfd != NULL)
80     result_bfd = prog_bfd;
81   else
82     {
83       result_bfd = bfd_openr (prog, 0);
84       if (result_bfd == NULL)
85         {
86           eprintf (callback, "%s: can't open \"%s\": %s\n", 
87                    myname, prog, bfd_errmsg (bfd_get_error ()));
88           return NULL;
89         }
90     }
91
92   if (!bfd_check_format (result_bfd, bfd_object)) 
93     {
94       eprintf (callback, "%s: \"%s\" is not an object file: %s\n",
95                myname, prog, bfd_errmsg (bfd_get_error ()));
96       /* Only close if we opened it.  */
97       if (prog_bfd == NULL)
98         bfd_close (result_bfd);
99       return NULL;
100     }
101
102   if (verbose_p)
103     start_time = time (NULL);
104
105   found_loadable_section = 0;
106   for (s = result_bfd->sections; s; s = s->next) 
107     {
108       if (s->flags & SEC_LOAD) 
109         {
110           bfd_size_type size;
111
112           size = bfd_get_section_size (s);
113           if (size > 0)
114             {
115               char *buffer;
116               bfd_vma lma;
117
118               buffer = malloc (size);
119               if (buffer == NULL)
120                 {
121                   eprintf (callback,
122                            "%s: insufficient memory to load \"%s\"\n",
123                            myname, prog);
124                   /* Only close if we opened it.  */
125                   if (prog_bfd == NULL)
126                     bfd_close (result_bfd);
127                   return NULL;
128                 }
129               if (lma_p)
130                 lma = bfd_section_lma (result_bfd, s);
131               else
132                 lma = bfd_section_vma (result_bfd, s);
133               if (verbose_p)
134                 {
135                   xprintf (callback, "Loading section %s, size 0x%lx %s ",
136                            bfd_get_section_name (result_bfd, s),
137                            (unsigned long) size,
138                            (lma_p ? "lma" : "vma"));
139                   xprintf_bfd_vma (callback, lma);
140                   xprintf (callback, "\n");
141                 }
142               data_count += size;
143               bfd_get_section_contents (result_bfd, s, buffer, 0, size);
144               do_write (sd, lma, buffer, size);
145               found_loadable_section = 1;
146               free (buffer);
147             }
148         }
149     }
150
151   if (!found_loadable_section)
152     {
153       eprintf (callback,
154                "%s: no loadable sections \"%s\"\n",
155                myname, prog);
156       return NULL;
157     }
158
159   if (verbose_p)
160     {
161       end_time = time (NULL);
162       xprintf (callback, "Start address ");
163       xprintf_bfd_vma (callback, bfd_get_start_address (result_bfd));
164       xprintf (callback, "\n");
165       report_transfer_performance (callback, data_count, start_time, end_time);
166     }
167
168   bfd_cache_close (result_bfd);
169
170   return result_bfd;
171 }
172
173 static void
174 xprintf VPARAMS ((host_callback *callback, const char *fmt, ...))
175 {
176   va_list ap;
177
178   VA_START (ap, fmt);
179
180   (*callback->vprintf_filtered) (callback, fmt, ap);
181
182   va_end (ap);
183 }
184
185 static void
186 eprintf VPARAMS ((host_callback *callback, const char *fmt, ...))
187 {
188   va_list ap;
189
190   VA_START (ap, fmt);
191
192   (*callback->evprintf_filtered) (callback, fmt, ap);
193
194   va_end (ap);
195 }
196
197 /* Report how fast the transfer went. */
198
199 static void
200 report_transfer_performance (callback, data_count, start_time, end_time)
201      host_callback *callback;
202      unsigned long data_count;
203      time_t start_time, end_time;
204 {
205   xprintf (callback, "Transfer rate: ");
206   if (end_time != start_time)
207     xprintf (callback, "%ld bits/sec",
208              (data_count * 8) / (end_time - start_time));
209   else
210     xprintf (callback, "%ld bits in <1 sec", (data_count * 8));
211   xprintf (callback, ".\n");
212 }
213
214 /* Print a bfd_vma.
215    This is intended to handle the vagaries of 32 vs 64 bits, etc.  */
216
217 static void
218 xprintf_bfd_vma (callback, vma)
219      host_callback *callback;
220      bfd_vma vma;
221 {
222   /* FIXME: for now */
223   xprintf (callback, "0x%lx", (unsigned long) vma);
224 }