summaryrefslogtreecommitdiff
path: root/sim/common/sim-load.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/common/sim-load.c')
-rw-r--r--sim/common/sim-load.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/sim/common/sim-load.c b/sim/common/sim-load.c
new file mode 100644
index 00000000000..22fb33b777b
--- /dev/null
+++ b/sim/common/sim-load.c
@@ -0,0 +1,239 @@
+/* Utility to load a file into the simulator.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* This is a standalone loader, independent of the sim-basic.h machinery,
+ as it is used by simulators that don't use it [though that doesn't mean
+ to suggest that they shouldn't :-)]. */
+
+#include "config.h"
+#include "ansidecl.h"
+#include <stdio.h> /* for NULL */
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <time.h>
+
+#include "sim-basics.h"
+#include "bfd.h"
+#include "sim-utils.h"
+
+#include "callback.h"
+#include "remote-sim.h"
+
+static void eprintf PARAMS ((host_callback *, const char *, ...));
+static void xprintf PARAMS ((host_callback *, const char *, ...));
+static void report_transfer_performance
+ PARAMS ((host_callback *, unsigned long, time_t, time_t));
+static void xprintf_bfd_vma PARAMS ((host_callback *, bfd_vma));
+
+/* Load program PROG into the simulator using the function DO_LOAD.
+ If PROG_BFD is non-NULL, the file has already been opened.
+ If VERBOSE_P is non-zero statistics are printed of each loaded section
+ and the transfer rate (for consistency with gdb).
+ If LMA_P is non-zero the program sections are loaded at the LMA
+ rather than the VMA
+ If this fails an error message is printed and NULL is returned.
+ If it succeeds the bfd is returned.
+ NOTE: For historical reasons, older hardware simulators incorrectly
+ write the program sections at LMA interpreted as a virtual address.
+ This is still accommodated for backward compatibility reasons. */
+
+
+bfd *
+sim_load_file (sd, myname, callback, prog, prog_bfd, verbose_p, lma_p, do_write)
+ SIM_DESC sd;
+ const char *myname;
+ host_callback *callback;
+ char *prog;
+ bfd *prog_bfd;
+ int verbose_p;
+ int lma_p;
+ sim_write_fn do_write;
+{
+ asection *s;
+ /* Record separately as we don't want to close PROG_BFD if it was passed. */
+ bfd *result_bfd;
+ time_t start_time = 0; /* Start and end times of download */
+ time_t end_time = 0;
+ unsigned long data_count = 0; /* Number of bytes transferred to memory */
+ int found_loadable_section;
+
+ if (prog_bfd != NULL)
+ result_bfd = prog_bfd;
+ else
+ {
+ result_bfd = bfd_openr (prog, 0);
+ if (result_bfd == NULL)
+ {
+ eprintf (callback, "%s: can't open \"%s\": %s\n",
+ myname, prog, bfd_errmsg (bfd_get_error ()));
+ return NULL;
+ }
+ }
+
+ if (!bfd_check_format (result_bfd, bfd_object))
+ {
+ eprintf (callback, "%s: \"%s\" is not an object file: %s\n",
+ myname, prog, bfd_errmsg (bfd_get_error ()));
+ /* Only close if we opened it. */
+ if (prog_bfd == NULL)
+ bfd_close (result_bfd);
+ return NULL;
+ }
+
+ if (verbose_p)
+ start_time = time (NULL);
+
+ found_loadable_section = 0;
+ for (s = result_bfd->sections; s; s = s->next)
+ {
+ if (s->flags & SEC_LOAD)
+ {
+ bfd_size_type size;
+
+ size = bfd_get_section_size_before_reloc (s);
+ if (size > 0)
+ {
+ char *buffer;
+ bfd_vma lma;
+
+ buffer = malloc (size);
+ if (buffer == NULL)
+ {
+ eprintf (callback,
+ "%s: insufficient memory to load \"%s\"\n",
+ myname, prog);
+ /* Only close if we opened it. */
+ if (prog_bfd == NULL)
+ bfd_close (result_bfd);
+ return NULL;
+ }
+ if (lma_p)
+ lma = bfd_section_lma (result_bfd, s);
+ else
+ lma = bfd_section_vma (result_bfd, s);
+ if (verbose_p)
+ {
+ xprintf (callback, "Loading section %s, size 0x%lx %s ",
+ bfd_get_section_name (result_bfd, s),
+ (unsigned long) size,
+ (lma_p ? "lma" : "vma"));
+ xprintf_bfd_vma (callback, lma);
+ xprintf (callback, "\n");
+ }
+ data_count += size;
+ bfd_get_section_contents (result_bfd, s, buffer, 0, size);
+ do_write (sd, lma, buffer, size);
+ found_loadable_section = 1;
+ free (buffer);
+ }
+ }
+ }
+
+ if (!found_loadable_section)
+ {
+ eprintf (callback,
+ "%s: no loadable sections \"%s\"\n",
+ myname, prog);
+ return NULL;
+ }
+
+ if (verbose_p)
+ {
+ end_time = time (NULL);
+ xprintf (callback, "Start address ");
+ xprintf_bfd_vma (callback, bfd_get_start_address (result_bfd));
+ xprintf (callback, "\n");
+ report_transfer_performance (callback, data_count, start_time, end_time);
+ }
+
+ return result_bfd;
+}
+
+static void
+xprintf VPARAMS ((host_callback *callback, const char *fmt, ...))
+{
+#ifndef ANSI_PROTOTYPES
+ host_callback *callback;
+ char *fmt;
+#endif
+ va_list ap;
+
+ VA_START (ap, fmt);
+#ifndef ANSI_PROTOTYPES
+ callback = va_arg (ap, host_callback *);
+ fmt = va_arg (ap, char *);
+#endif
+
+ (*callback->vprintf_filtered) (callback, fmt, ap);
+
+ va_end (ap);
+}
+
+static void
+eprintf VPARAMS ((host_callback *callback, const char *fmt, ...))
+{
+#ifndef ANSI_PROTOTYPES
+ host_callback *callback;
+ char *fmt;
+#endif
+ va_list ap;
+
+ VA_START (ap, fmt);
+#ifndef ANSI_PROTOTYPES
+ callback = va_arg (ap, host_callback *);
+ fmt = va_arg (ap, char *);
+#endif
+
+ (*callback->evprintf_filtered) (callback, fmt, ap);
+
+ va_end (ap);
+}
+
+/* Report how fast the transfer went. */
+
+static void
+report_transfer_performance (callback, data_count, start_time, end_time)
+ host_callback *callback;
+ unsigned long data_count;
+ time_t start_time, end_time;
+{
+ xprintf (callback, "Transfer rate: ");
+ if (end_time != start_time)
+ xprintf (callback, "%ld bits/sec",
+ (data_count * 8) / (end_time - start_time));
+ else
+ xprintf (callback, "%ld bits in <1 sec", (data_count * 8));
+ xprintf (callback, ".\n");
+}
+
+/* Print a bfd_vma.
+ This is intended to handle the vagaries of 32 vs 64 bits, etc. */
+
+static void
+xprintf_bfd_vma (callback, vma)
+ host_callback *callback;
+ bfd_vma vma;
+{
+ /* FIXME: for now */
+ xprintf (callback, "0x%lx", (unsigned long) vma);
+}