static SIM_RC
standard_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
			 char *arg, int is_command)
{
  int i,n;

  switch ((STANDARD_OPTIONS) opt)
    {
    case OPTION_VERBOSE:
      STATE_VERBOSE_P (sd) = 1;
      break;

#ifdef SIM_HAVE_BIENDIAN
    case OPTION_ENDIAN:
      if (strcmp (arg, "big") == 0)
	{
	  if (WITH_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
	    {
	      sim_io_eprintf (sd, "Simulator compiled for little endian only.\n");
	      return SIM_RC_FAIL;
	    }
	  /* FIXME:wip: Need to set something in STATE_CONFIG.  */
	  current_target_byte_order = BIG_ENDIAN;
	}
      else if (strcmp (arg, "little") == 0)
	{
	  if (WITH_TARGET_BYTE_ORDER == BIG_ENDIAN)
	    {
	      sim_io_eprintf (sd, "Simulator compiled for big endian only.\n");
	      return SIM_RC_FAIL;
	    }
	  /* FIXME:wip: Need to set something in STATE_CONFIG.  */
	  current_target_byte_order = LITTLE_ENDIAN;
	}
      else
	{
	  sim_io_eprintf (sd, "Invalid endian specification `%s'\n", arg);
	  return SIM_RC_FAIL;
	}
      break;
#endif

    case OPTION_ENVIRONMENT:
      if (strcmp (arg, "user") == 0)
	STATE_ENVIRONMENT (sd) = USER_ENVIRONMENT;
      else if (strcmp (arg, "virtual") == 0)
	STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT;
      else if (strcmp (arg, "operating") == 0)
	STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
      else
	{
	  sim_io_eprintf (sd, "Invalid environment specification `%s'\n", arg);
	  return SIM_RC_FAIL;
	}
      if (WITH_ENVIRONMENT != ALL_ENVIRONMENT
	  && WITH_ENVIRONMENT != STATE_ENVIRONMENT (sd))
	{
	  char *type;
	  switch (WITH_ENVIRONMENT)
	    {
	    case USER_ENVIRONMENT: type = "user"; break;
	    case VIRTUAL_ENVIRONMENT: type = "virtual"; break;
	    case OPERATING_ENVIRONMENT: type = "operating"; break;
	    }
	  sim_io_eprintf (sd, "Simulator compiled for the %s environment only.\n",
			  type);
	  return SIM_RC_FAIL;
	}
      break;

    case OPTION_ALIGNMENT:
      if (strcmp (arg, "strict") == 0)
	{
	  if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == STRICT_ALIGNMENT)
	    {
	      current_alignment = STRICT_ALIGNMENT;
	      break;
	    }
	}
      else if (strcmp (arg, "nonstrict") == 0)
	{
	  if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == NONSTRICT_ALIGNMENT)
	    {
	      current_alignment = NONSTRICT_ALIGNMENT;
	      break;
	    }
	}
      else if (strcmp (arg, "forced") == 0)
	{
	  if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == FORCED_ALIGNMENT)
	    {
	      current_alignment = FORCED_ALIGNMENT;
	      break;
	    }
	}
      else
	{
	  sim_io_eprintf (sd, "Invalid alignment specification `%s'\n", arg);
	  return SIM_RC_FAIL;
	}
      switch (WITH_ALIGNMENT)
	{
	case STRICT_ALIGNMENT:
	  sim_io_eprintf (sd, "Simulator compiled for strict alignment only.\n");
	  break;
	case NONSTRICT_ALIGNMENT:
	  sim_io_eprintf (sd, "Simulator compiled for nonstrict alignment only.\n");
	  break;
	case FORCED_ALIGNMENT:
	  sim_io_eprintf (sd, "Simulator compiled for forced alignment only.\n");
	  break;
	}
      return SIM_RC_FAIL;

    case OPTION_DEBUG:
      if (! WITH_DEBUG)
	sim_io_eprintf (sd, "Debugging not compiled in, `-D' ignored\n");
      else
	{
	  for (n = 0; n < MAX_NR_PROCESSORS; ++n)
	    for (i = 0; i < MAX_DEBUG_VALUES; ++i)
	      CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[i] = 1;
	}
      break;

    case OPTION_DEBUG_INSN :
      if (! WITH_DEBUG)
	sim_io_eprintf (sd, "Debugging not compiled in, `--debug-insn' ignored\n");
      else
	{
	  for (n = 0; n < MAX_NR_PROCESSORS; ++n)
	    CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[DEBUG_INSN_IDX] = 1;
	}
      break;

    case OPTION_DEBUG_FILE :
      if (! WITH_DEBUG)
	sim_io_eprintf (sd, "Debugging not compiled in, `--debug-file' ignored\n");
      else
	{
	  FILE *f = fopen (arg, "w");

	  if (f == NULL)
	    {
	      sim_io_eprintf (sd, "Unable to open debug output file `%s'\n", arg);
	      return SIM_RC_FAIL;
	    }
	  for (n = 0; n < MAX_NR_PROCESSORS; ++n)
	    CPU_DEBUG_FILE (STATE_CPU (sd, n)) = f;
	}
      break;

#ifdef SIM_H8300 /* FIXME: Can be moved to h8300 dir.  */
    case OPTION_H8300:
      set_h8300h (1,0);
      break;
    case OPTION_H8300S:
      set_h8300h (1,1);
      break;
#endif

#ifdef SIM_HAVE_FLATMEM
    case OPTION_MEM_SIZE:
      {
	unsigned long ul = strtol (arg, NULL, 0);
	/* 16384: some minimal amount */
	if (! isdigit (arg[0]) || ul < 16384)
	  {
	    sim_io_eprintf (sd, "Invalid memory size `%s'", arg);
	    return SIM_RC_FAIL;
	  }
	STATE_MEM_SIZE (sd) = ul;
      }
      break;
#endif

    case OPTION_DO_COMMAND:
      sim_do_command (sd, arg);
      break;

    case OPTION_ARCHITECTURE:
      {
	const struct bfd_arch_info *ap = bfd_scan_arch (arg);
	if (ap == NULL)
	  {
	    sim_io_eprintf (sd, "Architecture `%s' unknown\n", arg);
	    return SIM_RC_FAIL;
	  }
	STATE_ARCHITECTURE (sd) = ap;
	break;
      }

    case OPTION_ARCHITECTURE_INFO:
      {
	const char **list = bfd_arch_list();
	const char **lp;
	if (list == NULL)
	  abort ();
	sim_io_printf (sd, "Possible architectures:");
	for (lp = list; *lp != NULL; lp++)
	  sim_io_printf (sd, " %s", *lp);
	sim_io_printf (sd, "\n");
	free (list);
	break;
      }

    case OPTION_TARGET:
      {
	STATE_TARGET (sd) = xstrdup (arg);
	break;
      }

    case OPTION_LOAD_LMA:
      {
	STATE_LOAD_AT_LMA_P (sd) = 1;
	break;
      }

    case OPTION_LOAD_VMA:
      {
	STATE_LOAD_AT_LMA_P (sd) = 0;
	break;
      }

    case OPTION_HELP:
      sim_print_help (sd, is_command);
      if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
	exit (0);
      /* FIXME: 'twould be nice to do something similar if gdb.  */
      break;
    }

  return SIM_RC_OK;
}
Exemple #2
0
static void
bfin_user_init (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd,
		const char * const *argv, const char * const *env)
{
  /* XXX: Missing host -> target endian ...  */
  /* Linux starts the user app with the stack:
       argc
       argv[0]          -- pointers to the actual strings
       argv[1..N]
       NULL
       env[0]
       env[1..N]
       NULL
       auxvt[0].type    -- ELF Auxiliary Vector Table
       auxvt[0].value
       auxvt[1..N]
       AT_NULL
       0
       argv[0..N][0..M] -- actual argv/env strings
       env[0..N][0..M]
       FDPIC loadmaps   -- for FDPIC apps
     So set things up the same way.  */
  int i, argc, envc;
  bu32 argv_flat, env_flat;

  bu32 sp, sp_flat;

  /* start, at_phdr, at_phnum, at_base, at_entry, pt_dynamic  */
  bu32 elf_addrs[6];
  bu32 auxvt;
  bu32 exec_loadmap, ldso_loadmap;
  char *ldso_path;

  unsigned char null[4] = { 0, 0, 0, 0 };

  host_callback *cb = STATE_CALLBACK (sd);

  elf_addrs[0] = elf_addrs[4] = bfd_get_start_address (abfd);
  elf_addrs[1] = elf_addrs[2] = elf_addrs[3] = elf_addrs[5] = 0;

  /* Keep the load addresses consistent between runs.  Also make sure we make
     space for the fixed code region (part of the Blackfin Linux ABI).  */
  fdpic_load_offset = 0x1000;

  /* First try to load this as an FDPIC executable.  */
  sp = SPREG;
  if (!bfin_fdpic_load (sd, cpu, STATE_PROG_BFD (sd), &sp, elf_addrs, &ldso_path))
    goto skip_fdpic_init;
  exec_loadmap = sp;

  /* If that worked, then load the fixed code region.  We only do this for
     FDPIC ELFs atm because they are PIEs and let us relocate them without
     manual fixups.  FLAT files however require location processing which
     we do not do ourselves, and they link with a VMA of 0.  */
  sim_write (sd, 0x400, bfin_linux_fixed_code, sizeof (bfin_linux_fixed_code));

  /* If the FDPIC needs an interpreter, then load it up too.  */
  if (ldso_path)
    {
      const char *ldso_full_path = concat (simulator_sysroot, ldso_path, NULL);
      struct bfd *ldso_bfd;

      ldso_bfd = bfd_openr (ldso_full_path, STATE_TARGET (sd));
      if (!ldso_bfd)
	{
	  sim_io_eprintf (sd, "bfin-sim: bfd open failed: %s\n", ldso_full_path);
	  goto static_fdpic;
	}
      if (!bfd_check_format (ldso_bfd, bfd_object))
	sim_io_eprintf (sd, "bfin-sim: bfd format not valid: %s\n", ldso_full_path);
      bfd_set_arch_info (ldso_bfd, STATE_ARCHITECTURE (sd));

      if (!bfin_fdpic_load (sd, cpu, ldso_bfd, &sp, elf_addrs, &ldso_path))
	sim_io_eprintf (sd, "bfin-sim: FDPIC ldso failed to load: %s\n", ldso_full_path);
      if (ldso_path)
	sim_io_eprintf (sd, "bfin-sim: FDPIC ldso (%s) needs an interpreter (%s) !?\n",
			ldso_full_path, ldso_path);

      ldso_loadmap = sp;
    }
  else
 static_fdpic:
    ldso_loadmap = 0;

  /* Finally setup the registers required by the FDPIC ABI.  */
  SET_DREG (7, 0); /* Zero out FINI funcptr -- ldso will set this up.  */
  SET_PREG (0, exec_loadmap); /* Exec loadmap addr.  */
  SET_PREG (1, ldso_loadmap); /* Interp loadmap addr.  */
  SET_PREG (2, elf_addrs[5]); /* PT_DYNAMIC map addr.  */

  auxvt = 1;
  SET_SPREG (sp);
 skip_fdpic_init:
  sim_pc_set (cpu, elf_addrs[0]);

  /* Figure out how much storage the argv/env strings need.  */
  argc = count_argc (argv);
  if (argc == -1)
    argc = 0;
  argv_flat = argc; /* NUL bytes  */
  for (i = 0; i < argc; ++i)
    argv_flat += strlen (argv[i]);

  if (!env)
    env = simple_env;
  envc = count_argc (env);
  env_flat = envc; /* NUL bytes  */
  for (i = 0; i < envc; ++i)
    env_flat += strlen (env[i]);

  /* Push the Auxiliary Vector Table between argv/env and actual strings.  */
  sp_flat = sp = ALIGN (SPREG - argv_flat - env_flat - 4, 4);
  if (auxvt)
    {
# define AT_PUSH(at, val) \
  auxvt_size += 8; \
  sp -= 4; \
  auxvt = (val); \
  sim_write (sd, sp, (void *)&auxvt, 4); \
  sp -= 4; \
  auxvt = (at); \
  sim_write (sd, sp, (void *)&auxvt, 4)
      unsigned int egid = getegid (), gid = getgid ();
      unsigned int euid = geteuid (), uid = getuid ();
      bu32 auxvt_size = 0;
      AT_PUSH (AT_NULL, 0);
      AT_PUSH (AT_SECURE, egid != gid || euid != uid);
      AT_PUSH (AT_EGID, egid);
      AT_PUSH (AT_GID, gid);
      AT_PUSH (AT_EUID, euid);
      AT_PUSH (AT_UID, uid);
      AT_PUSH (AT_ENTRY, elf_addrs[4]);
      AT_PUSH (AT_FLAGS, 0);
      AT_PUSH (AT_BASE, elf_addrs[3]);
      AT_PUSH (AT_PHNUM, elf_addrs[2]);
      AT_PUSH (AT_PHENT, sizeof (Elf32_External_Phdr));
      AT_PUSH (AT_PHDR, elf_addrs[1]);
      AT_PUSH (AT_CLKTCK, 100); /* XXX: This ever not 100 ?  */
      AT_PUSH (AT_PAGESZ, 4096);
      AT_PUSH (AT_HWCAP, 0);
#undef AT_PUSH
    }
  SET_SPREG (sp);

  /* Push the argc/argv/env after the auxvt.  */
  sp -= ((1 + argc + 1 + envc + 1) * 4);
  SET_SPREG (sp);

  /* First push the argc value.  */
  sim_write (sd, sp, (void *)&argc, 4);
  sp += 4;

  /* Then the actual argv strings so we know where to point argv[].  */
  for (i = 0; i < argc; ++i)
    {
      unsigned len = strlen (argv[i]) + 1;
      sim_write (sd, sp_flat, (void *)argv[i], len);
      sim_write (sd, sp, (void *)&sp_flat, 4);
      sp_flat += len;
      sp += 4;
    }
  sim_write (sd, sp, null, 4);
  sp += 4;

  /* Then the actual env strings so we know where to point env[].  */
  for (i = 0; i < envc; ++i)
    {
      unsigned len = strlen (env[i]) + 1;
      sim_write (sd, sp_flat, (void *)env[i], len);
      sim_write (sd, sp, (void *)&sp_flat, 4);
      sp_flat += len;
      sp += 4;
    }

  /* Set some callbacks.  */
  cb->syscall_map = cb_linux_syscall_map;
  cb->errno_map = cb_linux_errno_map;
  cb->open_map = cb_linux_open_map;
  cb->signal_map = cb_linux_signal_map;
  cb->stat_map = stat_map_32 = cb_linux_stat_map_32;
  stat_map_64 = cb_linux_stat_map_64;
}