xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/sim-utils.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
14e98e3e1Schristos /* Miscellaneous simulator utilities.
2*88241920Schristos    Copyright (C) 1997-2024 Free Software Foundation, Inc.
34e98e3e1Schristos    Contributed by Cygnus Support.
44e98e3e1Schristos 
54e98e3e1Schristos This file is part of GDB, the GNU debugger.
64e98e3e1Schristos 
74e98e3e1Schristos This program is free software; you can redistribute it and/or modify
84e98e3e1Schristos it under the terms of the GNU General Public License as published by
94e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
104e98e3e1Schristos (at your option) any later version.
114e98e3e1Schristos 
124e98e3e1Schristos This program is distributed in the hope that it will be useful,
134e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
144e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
154e98e3e1Schristos GNU General Public License for more details.
164e98e3e1Schristos 
174e98e3e1Schristos You should have received a copy of the GNU General Public License
184e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
194e98e3e1Schristos 
204b169a6bSchristos /* This must come before any other includes.  */
214b169a6bSchristos #include "defs.h"
224e98e3e1Schristos 
234b169a6bSchristos #include <stdarg.h>
244e98e3e1Schristos #include <stdlib.h>
254b169a6bSchristos #include <string.h>
264e98e3e1Schristos #include <time.h>
274e98e3e1Schristos #ifdef HAVE_SYS_RESOURCE_H
284e98e3e1Schristos #include <sys/resource.h>
294e98e3e1Schristos #endif
304b169a6bSchristos #include <sys/time.h> /* needed by sys/resource.h */
314e98e3e1Schristos 
324e98e3e1Schristos #include "bfd.h"
334b169a6bSchristos #include "libiberty.h"
344b169a6bSchristos 
354b169a6bSchristos #include "sim-main.h"
364b169a6bSchristos #include "sim-assert.h"
374e98e3e1Schristos #include "sim-utils.h"
384e98e3e1Schristos 
394e98e3e1Schristos /* Allocate zero filled memory with xcalloc - xcalloc aborts if the
404e98e3e1Schristos    allocation fails.  */
414e98e3e1Schristos 
424e98e3e1Schristos void *
434e98e3e1Schristos zalloc (unsigned long size)
444e98e3e1Schristos {
454e98e3e1Schristos   return xcalloc (1, size);
464e98e3e1Schristos }
474e98e3e1Schristos 
484e98e3e1Schristos /* Allocate a sim_state struct.  */
494e98e3e1Schristos 
504e98e3e1Schristos SIM_DESC
514b169a6bSchristos sim_state_alloc_extra (SIM_OPEN_KIND kind, host_callback *callback,
524b169a6bSchristos 		       size_t extra_bytes)
534e98e3e1Schristos {
544e98e3e1Schristos   SIM_DESC sd = ZALLOC (struct sim_state);
554e98e3e1Schristos 
564e98e3e1Schristos   STATE_MAGIC (sd) = SIM_MAGIC_NUMBER;
574e98e3e1Schristos   STATE_CALLBACK (sd) = callback;
584e98e3e1Schristos   STATE_OPEN_KIND (sd) = kind;
594e98e3e1Schristos 
604b169a6bSchristos   if (extra_bytes)
614b169a6bSchristos     STATE_ARCH_DATA (sd) = zalloc (extra_bytes);
624b169a6bSchristos 
634e98e3e1Schristos #if 0
644e98e3e1Schristos   {
654e98e3e1Schristos     int cpu_nr;
664e98e3e1Schristos 
674e98e3e1Schristos     /* Initialize the back link from the cpu struct to the state struct.  */
684e98e3e1Schristos     /* ??? I can envision a design where the state struct contains an array
694e98e3e1Schristos        of pointers to cpu structs, rather than an array of structs themselves.
704e98e3e1Schristos        Implementing this is trickier as one may not know what to allocate until
714e98e3e1Schristos        one has parsed the args.  Parsing the args twice wouldn't be unreasonable,
724e98e3e1Schristos        IMHO.  If the state struct ever does contain an array of pointers then we
734e98e3e1Schristos        can't do this here.
744e98e3e1Schristos        ??? See also sim_post_argv_init*/
754e98e3e1Schristos     for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++)
764e98e3e1Schristos       {
774e98e3e1Schristos 	CPU_STATE (STATE_CPU (sd, cpu_nr)) = sd;
784e98e3e1Schristos 	CPU_INDEX (STATE_CPU (sd, cpu_nr)) = cpu_nr;
794e98e3e1Schristos       }
804e98e3e1Schristos   }
814e98e3e1Schristos #endif
824e98e3e1Schristos 
834e98e3e1Schristos #ifdef SIM_STATE_INIT
844e98e3e1Schristos   SIM_STATE_INIT (sd);
854e98e3e1Schristos #endif
864e98e3e1Schristos 
874e98e3e1Schristos   return sd;
884e98e3e1Schristos }
894e98e3e1Schristos 
904e98e3e1Schristos /* Free a sim_state struct.  */
914e98e3e1Schristos 
924e98e3e1Schristos void
934e98e3e1Schristos sim_state_free (SIM_DESC sd)
944e98e3e1Schristos {
95ba340e45Schristos   ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
964e98e3e1Schristos 
974e98e3e1Schristos #ifdef SIM_STATE_FREE
984e98e3e1Schristos   SIM_STATE_FREE (sd);
994e98e3e1Schristos #endif
1004e98e3e1Schristos 
1014b169a6bSchristos   free (STATE_PROG_FILE (sd));
1024b169a6bSchristos   free (STATE_PROG_ARGV0 (sd));
1034b169a6bSchristos   freeargv (STATE_PROG_ENVP (sd));
1044e98e3e1Schristos   free (sd);
1054e98e3e1Schristos }
1064e98e3e1Schristos 
1074e98e3e1Schristos /* Return a pointer to the cpu data for CPU_NAME, or NULL if not found.  */
1084e98e3e1Schristos 
1094e98e3e1Schristos sim_cpu *
1104e98e3e1Schristos sim_cpu_lookup (SIM_DESC sd, const char *cpu_name)
1114e98e3e1Schristos {
1124e98e3e1Schristos   int i;
1134e98e3e1Schristos 
1144e98e3e1Schristos   for (i = 0; i < MAX_NR_PROCESSORS; ++i)
1154e98e3e1Schristos     if (strcmp (cpu_name, CPU_NAME (STATE_CPU (sd, i))) == 0)
1164e98e3e1Schristos       return STATE_CPU (sd, i);
1174e98e3e1Schristos   return NULL;
1184e98e3e1Schristos }
1194e98e3e1Schristos 
1204e98e3e1Schristos /* Return the prefix to use for a CPU specific message (typically an
1214e98e3e1Schristos    error message).  */
1224e98e3e1Schristos 
1234e98e3e1Schristos const char *
1244e98e3e1Schristos sim_cpu_msg_prefix (sim_cpu *cpu)
1254e98e3e1Schristos {
1264e98e3e1Schristos   static char *prefix;
1274e98e3e1Schristos 
128*88241920Schristos   if (MAX_NR_PROCESSORS == 1)
129*88241920Schristos     return "";
130*88241920Schristos 
1314e98e3e1Schristos   if (prefix == NULL)
1324e98e3e1Schristos     {
133*88241920Schristos       SIM_DESC sd = CPU_STATE (cpu);
1344e98e3e1Schristos       int maxlen = 0;
135*88241920Schristos       int i;
136*88241920Schristos 
1374e98e3e1Schristos       for (i = 0; i < MAX_NR_PROCESSORS; ++i)
1384e98e3e1Schristos 	{
1394e98e3e1Schristos 	  int len = strlen (CPU_NAME (STATE_CPU (sd, i)));
1404e98e3e1Schristos 	  if (len > maxlen)
1414e98e3e1Schristos 	    maxlen = len;
1424e98e3e1Schristos 	}
1434e98e3e1Schristos       prefix = (char *) xmalloc (maxlen + 5);
1444e98e3e1Schristos     }
1454e98e3e1Schristos   sprintf (prefix, "%s: ", CPU_NAME (cpu));
146*88241920Schristos 
1474e98e3e1Schristos   return prefix;
1484e98e3e1Schristos }
1494e98e3e1Schristos 
1504e98e3e1Schristos /* Cover fn to sim_io_eprintf.  */
1514e98e3e1Schristos 
1524e98e3e1Schristos void
1534e98e3e1Schristos sim_io_eprintf_cpu (sim_cpu *cpu, const char *fmt, ...)
1544e98e3e1Schristos {
1554e98e3e1Schristos   SIM_DESC sd = CPU_STATE (cpu);
1564e98e3e1Schristos   va_list ap;
1574e98e3e1Schristos 
1584e98e3e1Schristos   va_start (ap, fmt);
1594e98e3e1Schristos   sim_io_eprintf (sd, "%s", sim_cpu_msg_prefix (cpu));
1604e98e3e1Schristos   sim_io_evprintf (sd, fmt, ap);
1614e98e3e1Schristos   va_end (ap);
1624e98e3e1Schristos }
1634e98e3e1Schristos 
1644e98e3e1Schristos /* Turn VALUE into a string with commas.  */
1654e98e3e1Schristos 
1664e98e3e1Schristos char *
1674e98e3e1Schristos sim_add_commas (char *buf, int sizeof_buf, unsigned long value)
1684e98e3e1Schristos {
1694e98e3e1Schristos   int comma = 3;
1704e98e3e1Schristos   char *endbuf = buf + sizeof_buf - 1;
1714e98e3e1Schristos 
1724e98e3e1Schristos   *--endbuf = '\0';
1734e98e3e1Schristos   do {
1744e98e3e1Schristos     if (comma-- == 0)
1754e98e3e1Schristos       {
1764e98e3e1Schristos 	*--endbuf = ',';
1774e98e3e1Schristos 	comma = 2;
1784e98e3e1Schristos       }
1794e98e3e1Schristos 
1804e98e3e1Schristos     *--endbuf = (value % 10) + '0';
1814e98e3e1Schristos   } while ((value /= 10) != 0);
1824e98e3e1Schristos 
1834e98e3e1Schristos   return endbuf;
1844e98e3e1Schristos }
1854e98e3e1Schristos 
1864e98e3e1Schristos /* Analyze PROG_NAME/PROG_BFD and set these fields in the state struct:
1874e98e3e1Schristos    STATE_ARCHITECTURE, if not set already and can be determined from the bfd
1884e98e3e1Schristos    STATE_PROG_BFD
1894e98e3e1Schristos    STATE_START_ADDR
1904e98e3e1Schristos    STATE_TEXT_SECTION
1914e98e3e1Schristos    STATE_TEXT_START
1924e98e3e1Schristos    STATE_TEXT_END
1934e98e3e1Schristos 
1944e98e3e1Schristos    PROG_NAME is the file name of the executable or NULL.
1954e98e3e1Schristos    PROG_BFD is its bfd or NULL.
1964e98e3e1Schristos 
1974e98e3e1Schristos    If both PROG_NAME and PROG_BFD are NULL, this function returns immediately.
1984e98e3e1Schristos    If PROG_BFD is not NULL, PROG_NAME is ignored.
1994e98e3e1Schristos 
2004e98e3e1Schristos    Implicit inputs: STATE_MY_NAME(sd), STATE_TARGET(sd),
2014e98e3e1Schristos                     STATE_ARCHITECTURE(sd).
2024e98e3e1Schristos 
2034e98e3e1Schristos    A new bfd is created so the app isn't required to keep its copy of the
2044e98e3e1Schristos    bfd open.  */
2054e98e3e1Schristos 
2064e98e3e1Schristos SIM_RC
207837edd6bSchristos sim_analyze_program (SIM_DESC sd, const char *prog_name, bfd *prog_bfd)
2084e98e3e1Schristos {
2094e98e3e1Schristos   asection *s;
2104e98e3e1Schristos   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
2114e98e3e1Schristos 
2124e98e3e1Schristos   if (prog_bfd != NULL)
2134e98e3e1Schristos     {
2144e98e3e1Schristos       if (prog_bfd == STATE_PROG_BFD (sd))
2154e98e3e1Schristos 	/* already analyzed */
2164e98e3e1Schristos 	return SIM_RC_OK;
2174e98e3e1Schristos       else
2184e98e3e1Schristos 	/* duplicate needed, save the name of the file to be re-opened */
2194e98e3e1Schristos 	prog_name = bfd_get_filename (prog_bfd);
2204e98e3e1Schristos     }
2214e98e3e1Schristos 
2224e98e3e1Schristos   /* do we need to duplicate anything? */
2234e98e3e1Schristos   if (prog_name == NULL)
2244e98e3e1Schristos     return SIM_RC_OK;
2254e98e3e1Schristos 
2264e98e3e1Schristos   /* open a new copy of the prog_bfd */
2274e98e3e1Schristos   prog_bfd = bfd_openr (prog_name, STATE_TARGET (sd));
2284e98e3e1Schristos   if (prog_bfd == NULL)
2294e98e3e1Schristos     {
2304e98e3e1Schristos       sim_io_eprintf (sd, "%s: can't open \"%s\": %s\n",
2314e98e3e1Schristos 		      STATE_MY_NAME (sd),
2324e98e3e1Schristos 		      prog_name,
2334e98e3e1Schristos 		      bfd_errmsg (bfd_get_error ()));
2344e98e3e1Schristos       return SIM_RC_FAIL;
2354e98e3e1Schristos     }
2364e98e3e1Schristos   if (!bfd_check_format (prog_bfd, bfd_object))
2374e98e3e1Schristos     {
2384e98e3e1Schristos       sim_io_eprintf (sd, "%s: \"%s\" is not an object file: %s\n",
2394e98e3e1Schristos 		      STATE_MY_NAME (sd),
2404e98e3e1Schristos 		      prog_name,
2414e98e3e1Schristos 		      bfd_errmsg (bfd_get_error ()));
2424e98e3e1Schristos       bfd_close (prog_bfd);
2434e98e3e1Schristos       return SIM_RC_FAIL;
2444e98e3e1Schristos     }
2454e98e3e1Schristos   if (STATE_ARCHITECTURE (sd) != NULL)
2464e98e3e1Schristos     bfd_set_arch_info (prog_bfd, STATE_ARCHITECTURE (sd));
2474e98e3e1Schristos   else
2484e98e3e1Schristos     {
2494e98e3e1Schristos       if (bfd_get_arch (prog_bfd) != bfd_arch_unknown
2504e98e3e1Schristos 	  && bfd_get_arch (prog_bfd) != bfd_arch_obscure)
2514e98e3e1Schristos 	{
2524e98e3e1Schristos 	  STATE_ARCHITECTURE (sd) = bfd_get_arch_info (prog_bfd);
2534e98e3e1Schristos 	}
2544e98e3e1Schristos     }
2554e98e3e1Schristos 
2564e98e3e1Schristos   /* update the sim structure */
2574e98e3e1Schristos   if (STATE_PROG_BFD (sd) != NULL)
2584e98e3e1Schristos     bfd_close (STATE_PROG_BFD (sd));
2594e98e3e1Schristos   STATE_PROG_BFD (sd) = prog_bfd;
2604e98e3e1Schristos   STATE_START_ADDR (sd) = bfd_get_start_address (prog_bfd);
2614e98e3e1Schristos 
2624e98e3e1Schristos   for (s = prog_bfd->sections; s; s = s->next)
2638dffb485Schristos     if (strcmp (bfd_section_name (s), ".text") == 0)
2644e98e3e1Schristos       {
2654e98e3e1Schristos 	STATE_TEXT_SECTION (sd) = s;
2668dffb485Schristos 	STATE_TEXT_START (sd) = bfd_section_vma (s);
2678dffb485Schristos 	STATE_TEXT_END (sd) = STATE_TEXT_START (sd) + bfd_section_size (s);
2684e98e3e1Schristos 	break;
2694e98e3e1Schristos       }
2704e98e3e1Schristos 
2714e98e3e1Schristos   bfd_cache_close (prog_bfd);
2724e98e3e1Schristos 
2734e98e3e1Schristos   return SIM_RC_OK;
2744e98e3e1Schristos }
2754e98e3e1Schristos 
2764e98e3e1Schristos /* Simulator timing support.  */
2774e98e3e1Schristos 
2784e98e3e1Schristos /* Called before sim_elapsed_time_since to get a reference point.  */
2794e98e3e1Schristos 
2804e98e3e1Schristos SIM_ELAPSED_TIME
2814e98e3e1Schristos sim_elapsed_time_get (void)
2824e98e3e1Schristos {
2834e98e3e1Schristos #ifdef HAVE_GETRUSAGE
2844e98e3e1Schristos   struct rusage mytime;
2854e98e3e1Schristos   if (getrusage (RUSAGE_SELF, &mytime) == 0)
2864e98e3e1Schristos     return 1 + (SIM_ELAPSED_TIME) (((double) mytime.ru_utime.tv_sec * 1000) + (((double) mytime.ru_utime.tv_usec + 500) / 1000));
2874e98e3e1Schristos   return 1;
2884e98e3e1Schristos #else
2894e98e3e1Schristos #ifdef HAVE_TIME
2904e98e3e1Schristos   return 1 + (SIM_ELAPSED_TIME) time ((time_t) 0);
2914e98e3e1Schristos #else
2924e98e3e1Schristos   return 1;
2934e98e3e1Schristos #endif
2944e98e3e1Schristos #endif
2954e98e3e1Schristos }
2964e98e3e1Schristos 
2974e98e3e1Schristos /* Return the elapsed time in milliseconds since START.
2984e98e3e1Schristos    The actual time may be cpu usage (preferred) or wall clock.  */
2994e98e3e1Schristos 
3004e98e3e1Schristos unsigned long
3014e98e3e1Schristos sim_elapsed_time_since (SIM_ELAPSED_TIME start)
3024e98e3e1Schristos {
3034e98e3e1Schristos #ifdef HAVE_GETRUSAGE
3044e98e3e1Schristos   return sim_elapsed_time_get () - start;
3054e98e3e1Schristos #else
3064e98e3e1Schristos #ifdef HAVE_TIME
3074e98e3e1Schristos   return (sim_elapsed_time_get () - start) * 1000;
3084e98e3e1Schristos #else
3094e98e3e1Schristos   return 0;
3104e98e3e1Schristos #endif
3114e98e3e1Schristos #endif
3124e98e3e1Schristos }
3134e98e3e1Schristos 
3144e98e3e1Schristos 
3154e98e3e1Schristos 
3164e98e3e1Schristos /* do_command but with printf style formatting of the arguments */
3174e98e3e1Schristos void
3184e98e3e1Schristos sim_do_commandf (SIM_DESC sd,
3194e98e3e1Schristos 		 const char *fmt,
3204e98e3e1Schristos 		 ...)
3214e98e3e1Schristos {
3224e98e3e1Schristos   va_list ap;
3234e98e3e1Schristos   char *buf;
324ba340e45Schristos   int ret;
325ba340e45Schristos 
3264e98e3e1Schristos   va_start (ap, fmt);
327ba340e45Schristos   ret = vasprintf (&buf, fmt, ap);
328ba340e45Schristos   va_end (ap);
329ba340e45Schristos 
330ba340e45Schristos   if (ret < 0)
3314e98e3e1Schristos     {
3324e98e3e1Schristos       sim_io_eprintf (sd, "%s: asprintf failed for `%s'\n",
3334e98e3e1Schristos 		      STATE_MY_NAME (sd), fmt);
3344e98e3e1Schristos       return;
3354e98e3e1Schristos     }
336ba340e45Schristos 
3374e98e3e1Schristos   sim_do_command (sd, buf);
3384e98e3e1Schristos   free (buf);
3394e98e3e1Schristos }
3404e98e3e1Schristos 
3414e98e3e1Schristos 
3424e98e3e1Schristos /* sim-basics.h defines a number of enumerations, convert each of them
3434e98e3e1Schristos    to a string representation */
3444e98e3e1Schristos const char *
3454e98e3e1Schristos map_to_str (unsigned map)
3464e98e3e1Schristos {
3474e98e3e1Schristos   switch (map)
3484e98e3e1Schristos     {
3494e98e3e1Schristos     case read_map: return "read";
3504e98e3e1Schristos     case write_map: return "write";
3514e98e3e1Schristos     case exec_map: return "exec";
3524e98e3e1Schristos     case io_map: return "io";
3534e98e3e1Schristos     default:
3544e98e3e1Schristos       {
3558dffb485Schristos 	static char str[16];
3568dffb485Schristos 	snprintf (str, sizeof(str), "(%ld)", (long) map);
3574e98e3e1Schristos 	return str;
3584e98e3e1Schristos       }
3594e98e3e1Schristos     }
3604e98e3e1Schristos }
3614e98e3e1Schristos 
3624e98e3e1Schristos const char *
3634e98e3e1Schristos access_to_str (unsigned access)
3644e98e3e1Schristos {
3654e98e3e1Schristos   switch (access)
3664e98e3e1Schristos     {
3674e98e3e1Schristos     case access_invalid: return "invalid";
3684e98e3e1Schristos     case access_read: return "read";
3694e98e3e1Schristos     case access_write: return "write";
3704e98e3e1Schristos     case access_exec: return "exec";
3714e98e3e1Schristos     case access_io: return "io";
3724e98e3e1Schristos     case access_read_write: return "read_write";
3734e98e3e1Schristos     case access_read_exec: return "read_exec";
3744e98e3e1Schristos     case access_write_exec: return "write_exec";
3754e98e3e1Schristos     case access_read_write_exec: return "read_write_exec";
3764e98e3e1Schristos     case access_read_io: return "read_io";
3774e98e3e1Schristos     case access_write_io: return "write_io";
3784e98e3e1Schristos     case access_read_write_io: return "read_write_io";
3794e98e3e1Schristos     case access_exec_io: return "exec_io";
3804e98e3e1Schristos     case access_read_exec_io: return "read_exec_io";
3814e98e3e1Schristos     case access_write_exec_io: return "write_exec_io";
3824e98e3e1Schristos     case access_read_write_exec_io: return "read_write_exec_io";
3834e98e3e1Schristos     default:
3844e98e3e1Schristos       {
3858dffb485Schristos 	static char str[16];
3868dffb485Schristos 	snprintf (str, sizeof(str), "(%ld)", (long) access);
3874e98e3e1Schristos 	return str;
3884e98e3e1Schristos       }
3894e98e3e1Schristos     }
3904e98e3e1Schristos }
3914e98e3e1Schristos 
3924e98e3e1Schristos const char *
3934e98e3e1Schristos transfer_to_str (unsigned transfer)
3944e98e3e1Schristos {
3954e98e3e1Schristos   switch (transfer)
3964e98e3e1Schristos     {
3974e98e3e1Schristos     case read_transfer: return "read";
3984e98e3e1Schristos     case write_transfer: return "write";
3994e98e3e1Schristos     default: return "(error)";
4004e98e3e1Schristos     }
4014e98e3e1Schristos }
402