diff options
Diffstat (limited to 'sim/common/sim-load.c')
-rw-r--r-- | sim/common/sim-load.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/sim/common/sim-load.c b/sim/common/sim-load.c new file mode 100644 index 0000000..0fc1b4c --- /dev/null +++ b/sim/common/sim-load.c @@ -0,0 +1,209 @@ +/* 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. */ + +#include "config.h" +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <time.h> +#include "ansidecl.h" +#include "bfd.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. + 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 this fails an error message is printed and NULL is returned. + If it succeeds the bfd is returned. */ + +/* FIXME: Where can we put a prototype for this? */ + +bfd * +sim_load_file (sd, myname, callback, prog, prog_bfd, verbose_p) + SIM_DESC sd; + char *myname; + host_callback *callback; + char *prog; + bfd *prog_bfd; +{ + asection *s; + /* Record separately as we don't want to close PROG_BFD if it was passed. */ + bfd *result_bfd; + time_t start_time, end_time; /* Start and end times of download */ + unsigned long data_count = 0; /* Number of bytes transferred to memory */ + + 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); + + 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; + } + /* Before you change this to bfd_section_lma, make sure + the arm-pe simulator still works. */ + lma = bfd_section_vma (result_bfd, s); + if (verbose_p) + { + xprintf (callback, "Loading section %s, size 0x%lx lma ", + bfd_get_section_name (result_bfd, s), + (unsigned long) size); + xprintf_bfd_vma (callback, lma); + xprintf (callback, "\n"); + } + data_count += size; + bfd_get_section_contents (result_bfd, s, buffer, 0, size); + sim_write (sd, lma, buffer, size); + free (buffer); + } + } + } + + 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 __STDC__ + host_callback *callback; + char *fmt; +#endif + va_list ap; + + VA_START (ap, fmt); +#ifndef __STDC__ + 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 __STDC__ + host_callback *callback; + char *fmt; +#endif + va_list ap; + + VA_START (ap, fmt); +#ifndef __STDC__ + 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); +} |