xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/sim-load.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
14e98e3e1Schristos /* Utility to load a file into the simulator.
2*88241920Schristos    Copyright (C) 1997-2024 Free Software Foundation, Inc.
34e98e3e1Schristos 
44e98e3e1Schristos This program is free software; you can redistribute it and/or modify
54e98e3e1Schristos it under the terms of the GNU General Public License as published by
64e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
74e98e3e1Schristos (at your option) any later version.
84e98e3e1Schristos 
94e98e3e1Schristos This program is distributed in the hope that it will be useful,
104e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
114e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
124e98e3e1Schristos GNU General Public License for more details.
134e98e3e1Schristos 
144e98e3e1Schristos You should have received a copy of the GNU General Public License
154e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
164e98e3e1Schristos 
174e98e3e1Schristos /* This is a standalone loader, independent of the sim-basic.h machinery,
184e98e3e1Schristos    as it is used by simulators that don't use it [though that doesn't mean
194e98e3e1Schristos    to suggest that they shouldn't :-)].  */
204e98e3e1Schristos 
214b169a6bSchristos /* This must come before any other includes.  */
224b169a6bSchristos #include "defs.h"
234b169a6bSchristos 
244e98e3e1Schristos #include <stdarg.h>
254b169a6bSchristos #include <stdio.h> /* for NULL */
264e98e3e1Schristos #include <stdlib.h>
274e98e3e1Schristos #include <time.h>
284e98e3e1Schristos 
294b169a6bSchristos #include "ansidecl.h"
304e98e3e1Schristos #include "bfd.h"
314e98e3e1Schristos 
324b169a6bSchristos #include "sim/callback.h"
334b169a6bSchristos #include "sim/sim.h"
344b169a6bSchristos #include "sim-utils.h"
354e98e3e1Schristos 
3603467a24Schristos static void eprintf (host_callback *, const char *, ...);
3703467a24Schristos static void xprintf (host_callback *, const char *, ...);
384e98e3e1Schristos static void report_transfer_performance
3903467a24Schristos   (host_callback *, unsigned long, time_t, time_t);
404e98e3e1Schristos 
414b169a6bSchristos /* Load program PROG into the simulator using the function DO_WRITE.
424e98e3e1Schristos    If PROG_BFD is non-NULL, the file has already been opened.
434e98e3e1Schristos    If VERBOSE_P is non-zero statistics are printed of each loaded section
444e98e3e1Schristos    and the transfer rate (for consistency with gdb).
454e98e3e1Schristos    If LMA_P is non-zero the program sections are loaded at the LMA
464e98e3e1Schristos    rather than the VMA
474e98e3e1Schristos    If this fails an error message is printed and NULL is returned.
484e98e3e1Schristos    If it succeeds the bfd is returned.
494e98e3e1Schristos    NOTE: For historical reasons, older hardware simulators incorrectly
504e98e3e1Schristos    write the program sections at LMA interpreted as a virtual address.
514e98e3e1Schristos    This is still accommodated for backward compatibility reasons. */
524e98e3e1Schristos 
534e98e3e1Schristos 
544e98e3e1Schristos bfd *
55837edd6bSchristos sim_load_file (SIM_DESC sd, const char *myname, host_callback *callback,
56837edd6bSchristos 	       const char *prog, bfd *prog_bfd, int verbose_p, int lma_p,
57837edd6bSchristos 	       sim_write_fn do_write)
584e98e3e1Schristos {
594e98e3e1Schristos   asection *s;
604e98e3e1Schristos   /* Record separately as we don't want to close PROG_BFD if it was passed.  */
614e98e3e1Schristos   bfd *result_bfd;
624e98e3e1Schristos   time_t start_time = 0;	/* Start and end times of download */
634e98e3e1Schristos   time_t end_time = 0;
644e98e3e1Schristos   unsigned long data_count = 0;	/* Number of bytes transferred to memory */
654e98e3e1Schristos   int found_loadable_section;
664e98e3e1Schristos 
674e98e3e1Schristos   if (prog_bfd != NULL)
684e98e3e1Schristos     result_bfd = prog_bfd;
694e98e3e1Schristos   else
704e98e3e1Schristos     {
714e98e3e1Schristos       result_bfd = bfd_openr (prog, 0);
724e98e3e1Schristos       if (result_bfd == NULL)
734e98e3e1Schristos 	{
744e98e3e1Schristos 	  eprintf (callback, "%s: can't open \"%s\": %s\n",
754e98e3e1Schristos 		   myname, prog, bfd_errmsg (bfd_get_error ()));
764e98e3e1Schristos 	  return NULL;
774e98e3e1Schristos 	}
784e98e3e1Schristos     }
794e98e3e1Schristos 
804e98e3e1Schristos   if (!bfd_check_format (result_bfd, bfd_object))
814e98e3e1Schristos     {
824e98e3e1Schristos       eprintf (callback, "%s: \"%s\" is not an object file: %s\n",
834e98e3e1Schristos 	       myname, prog, bfd_errmsg (bfd_get_error ()));
844e98e3e1Schristos       /* Only close if we opened it.  */
854e98e3e1Schristos       if (prog_bfd == NULL)
864e98e3e1Schristos 	bfd_close (result_bfd);
874e98e3e1Schristos       return NULL;
884e98e3e1Schristos     }
894e98e3e1Schristos 
904e98e3e1Schristos   if (verbose_p)
914e98e3e1Schristos     start_time = time (NULL);
924e98e3e1Schristos 
934e98e3e1Schristos   found_loadable_section = 0;
944e98e3e1Schristos   for (s = result_bfd->sections; s; s = s->next)
954e98e3e1Schristos     {
964e98e3e1Schristos       if (s->flags & SEC_LOAD)
974e98e3e1Schristos 	{
984e98e3e1Schristos 	  bfd_size_type size;
994e98e3e1Schristos 
1008dffb485Schristos 	  size = bfd_section_size (s);
1014e98e3e1Schristos 	  if (size > 0)
1024e98e3e1Schristos 	    {
1034e98e3e1Schristos 	      unsigned char *buffer;
1044e98e3e1Schristos 	      bfd_vma lma;
1054e98e3e1Schristos 
1064e98e3e1Schristos 	      buffer = malloc (size);
1074e98e3e1Schristos 	      if (buffer == NULL)
1084e98e3e1Schristos 		{
1094e98e3e1Schristos 		  eprintf (callback,
1104e98e3e1Schristos 			   "%s: insufficient memory to load \"%s\"\n",
1114e98e3e1Schristos 			   myname, prog);
1124e98e3e1Schristos 		  /* Only close if we opened it.  */
1134e98e3e1Schristos 		  if (prog_bfd == NULL)
1144e98e3e1Schristos 		    bfd_close (result_bfd);
1154e98e3e1Schristos 		  return NULL;
1164e98e3e1Schristos 		}
1174e98e3e1Schristos 	      if (lma_p)
1188dffb485Schristos 		lma = bfd_section_lma (s);
1194e98e3e1Schristos 	      else
1208dffb485Schristos 		lma = bfd_section_vma (s);
1214e98e3e1Schristos 	      if (verbose_p)
1224e98e3e1Schristos 		{
1234b169a6bSchristos 		  xprintf (callback,
1244b169a6bSchristos 			   "Loading section %s, size 0x%" PRIx64
1254b169a6bSchristos 			   " %s %" PRIx64 "\n",
1264b169a6bSchristos 			   bfd_section_name (s), (uint64_t) size,
1274b169a6bSchristos 			   lma_p ? "lma" : "vma", (uint64_t) lma);
1284e98e3e1Schristos 		}
1294e98e3e1Schristos 	      data_count += size;
1304e98e3e1Schristos 	      bfd_get_section_contents (result_bfd, s, buffer, 0, size);
1314e98e3e1Schristos 	      do_write (sd, lma, buffer, size);
1324e98e3e1Schristos 	      found_loadable_section = 1;
1334e98e3e1Schristos 	      free (buffer);
1344e98e3e1Schristos 	    }
1354e98e3e1Schristos 	}
1364e98e3e1Schristos     }
1374e98e3e1Schristos 
1384e98e3e1Schristos   if (!found_loadable_section)
1394e98e3e1Schristos     {
1404e98e3e1Schristos       eprintf (callback,
1414e98e3e1Schristos 	       "%s: no loadable sections \"%s\"\n",
1424e98e3e1Schristos 	       myname, prog);
1434e98e3e1Schristos       return NULL;
1444e98e3e1Schristos     }
1454e98e3e1Schristos 
1464e98e3e1Schristos   if (verbose_p)
1474e98e3e1Schristos     {
1484e98e3e1Schristos       end_time = time (NULL);
1494b169a6bSchristos       xprintf (callback, "Start address %" PRIx64 "\n",
1504b169a6bSchristos 	       (uint64_t) bfd_get_start_address (result_bfd));
1514e98e3e1Schristos       report_transfer_performance (callback, data_count, start_time, end_time);
1524e98e3e1Schristos     }
1534e98e3e1Schristos 
1544e98e3e1Schristos   bfd_cache_close (result_bfd);
1554e98e3e1Schristos 
1564e98e3e1Schristos   return result_bfd;
1574e98e3e1Schristos }
1584e98e3e1Schristos 
1594e98e3e1Schristos static void
16003467a24Schristos xprintf (host_callback *callback, const char *fmt, ...)
1614e98e3e1Schristos {
1624e98e3e1Schristos   va_list ap;
1634e98e3e1Schristos 
16403467a24Schristos   va_start (ap, fmt);
1654e98e3e1Schristos 
1664e98e3e1Schristos   (*callback->vprintf_filtered) (callback, fmt, ap);
1674e98e3e1Schristos 
1684e98e3e1Schristos   va_end (ap);
1694e98e3e1Schristos }
1704e98e3e1Schristos 
1714e98e3e1Schristos static void
17203467a24Schristos eprintf (host_callback *callback, const char *fmt, ...)
1734e98e3e1Schristos {
1744e98e3e1Schristos   va_list ap;
1754e98e3e1Schristos 
17603467a24Schristos   va_start (ap, fmt);
1774e98e3e1Schristos 
1784e98e3e1Schristos   (*callback->evprintf_filtered) (callback, fmt, ap);
1794e98e3e1Schristos 
1804e98e3e1Schristos   va_end (ap);
1814e98e3e1Schristos }
1824e98e3e1Schristos 
1834e98e3e1Schristos /* Report how fast the transfer went. */
1844e98e3e1Schristos 
1854e98e3e1Schristos static void
186837edd6bSchristos report_transfer_performance (host_callback *callback, unsigned long data_count,
187837edd6bSchristos 			     time_t start_time, time_t end_time)
1884e98e3e1Schristos {
1894e98e3e1Schristos   xprintf (callback, "Transfer rate: ");
1904e98e3e1Schristos   if (end_time != start_time)
1914e98e3e1Schristos     xprintf (callback, "%ld bits/sec",
1924e98e3e1Schristos 	     (data_count * 8) / (end_time - start_time));
1934e98e3e1Schristos   else
1944e98e3e1Schristos     xprintf (callback, "%ld bits in <1 sec", (data_count * 8));
1954e98e3e1Schristos   xprintf (callback, ".\n");
1964e98e3e1Schristos }
197