Пример #1
0
/* Sets the default target if none has been given already.  An empty
   string as the default target in interpreted as stdin.  The string
   is quoted for MAKE.  */
void
deps_add_default_target (struct deps *d, const char *tgt)
{
  /* Only if we have no targets.  */
  if (d->ntargets)
    return;

  if (tgt[0] == '\0')
    deps_add_target (d, "-", 1);
  else
    {
#ifndef TARGET_OBJECT_SUFFIX
# define TARGET_OBJECT_SUFFIX ".o"
#endif
      const char *start = lbasename (tgt);
      char *o = alloca (strlen (start) + strlen (TARGET_OBJECT_SUFFIX) + 1);
      char *suffix;

      strcpy (o, start);

      suffix = strrchr (o, '.');
      if (!suffix)
        suffix = o + strlen (o);
      strcpy (suffix, TARGET_OBJECT_SUFFIX);

      deps_add_target (d, o, 1);
    }
}
Пример #2
0
static void
handle_pragma_interface (cpp_reader* /*dfile*/)
{
  tree fname = parse_strconst_pragma ("interface", 1);
  struct c_fileinfo *finfo;
  const char *filename;

  if (fname == error_mark_node)
    return;
  else if (fname == 0)
    filename = lbasename (LOCATION_FILE (input_location));
  else
    filename = TREE_STRING_POINTER (fname);

  finfo = get_fileinfo (LOCATION_FILE (input_location));

  if (impl_file_chain == 0)
    {
      /* If this is zero at this point, then we are
	 auto-implementing.  */
      if (main_input_filename == 0)
	main_input_filename = LOCATION_FILE (input_location);
    }

  finfo->interface_only = interface_strcmp (filename);
  /* If MULTIPLE_SYMBOL_SPACES is set, we cannot assume that we can see
     a definition in another file.  */
  if (!MULTIPLE_SYMBOL_SPACES || !finfo->interface_only)
    finfo->interface_unknown = 0;
}
Пример #3
0
/*
 * Create a string which describes a position in a source file.
 */
const char *
mkpos(pos_t *posp)
{
	size_t	len;
	const	char *fn;
	static	char	*buf;
	static	size_t	blen = 0;
	int	qm, src, line;

	if (Hflag && posp->p_src != posp->p_isrc) {
		src = posp->p_isrc;
		line = posp->p_iline;
	} else {
		src = posp->p_src;
		line = posp->p_line;
	}
	qm = !Hflag && posp->p_src != posp->p_isrc;

	len = strlen(fn = lbasename(fnames[src]));
	len += 3 * sizeof (u_short) + 4;

	if (len > blen)
		buf = xrealloc(buf, blen = len);
	if (line != 0) {
		(void)sprintf(buf, "%s%s(%d)",
			      fn, qm ? "?" : "", line);
	} else {
		(void)sprintf(buf, "%s", fn);
	}

	return (buf);
}
Пример #4
0
SIM_RC
sim_pre_argv_init (SIM_DESC sd, const char *myname)
{
  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
  SIM_ASSERT (STATE_MODULES (sd) == NULL);

  STATE_MY_NAME (sd) = lbasename (myname);

  /* Set the cpu names to default values.  */
  {
    int i;
    for (i = 0; i < MAX_NR_PROCESSORS; ++i)
      {
	char *name;
	if (asprintf (&name, "cpu%d", i) < 0)
	  return SIM_RC_FAIL;
	CPU_NAME (STATE_CPU (sd, i)) = name;
      }
  }

  sim_config_default (sd);

  /* Install all configured in modules.  */
  if (sim_module_install (sd) != SIM_RC_OK)
    return SIM_RC_FAIL;

  return SIM_RC_OK;
}
Пример #5
0
bool nesc_filename(const char *name)
{
  char *dot = strrchr(lbasename(name), '.');

  if (dot)
    {
      if (!strcmp(dot, ".nc"))
	return TRUE;
    }
  return FALSE; /* C by default */
}
Пример #6
0
static char *
get_plugin_base_name (const char *full_name)
{
  /* First get the base name part of the full-path name, i.e. NAME.so.  */
  char *base_name = xstrdup (lbasename (full_name));

  /* Then get rid of '.so' part of the name.  */
  strip_off_ending (base_name, strlen (base_name));

  return base_name;
}
Пример #7
0
static gdb_bfd_ref_ptr
macho_check_dsym (struct objfile *objfile, std::string *filenamep)
{
  size_t name_len = strlen (objfile_name (objfile));
  size_t dsym_len = strlen (DSYM_SUFFIX);
  const char *base_name = lbasename (objfile_name (objfile));
  size_t base_len = strlen (base_name);
  char *dsym_filename = (char *) alloca (name_len + dsym_len + base_len + 1);
  bfd_mach_o_load_command *main_uuid;
  bfd_mach_o_load_command *dsym_uuid;

  strcpy (dsym_filename, objfile_name (objfile));
  strcpy (dsym_filename + name_len, DSYM_SUFFIX);
  strcpy (dsym_filename + name_len + dsym_len, base_name);

  if (access (dsym_filename, R_OK) != 0)
    return NULL;

  if (bfd_mach_o_lookup_command (objfile->obfd,
                                 BFD_MACH_O_LC_UUID, &main_uuid) == 0)
    {
      warning (_("can't find UUID in %s"), objfile_name (objfile));
      return NULL;
    }
  gdb_bfd_ref_ptr dsym_bfd (gdb_bfd_openr (dsym_filename, gnutarget));
  if (dsym_bfd == NULL)
    {
      warning (_("can't open dsym file %s"), dsym_filename);
      return NULL;
    }

  if (!bfd_check_format (dsym_bfd.get (), bfd_object))
    {
      warning (_("bad dsym file format: %s"), bfd_errmsg (bfd_get_error ()));
      return NULL;
    }

  if (bfd_mach_o_lookup_command (dsym_bfd.get (),
                                 BFD_MACH_O_LC_UUID, &dsym_uuid) == 0)
    {
      warning (_("can't find UUID in %s"), dsym_filename);
      return NULL;
    }
  if (memcmp (dsym_uuid->command.uuid.uuid, main_uuid->command.uuid.uuid,
              sizeof (main_uuid->command.uuid.uuid)))
    {
      warning (_("dsym file UUID doesn't match the one in %s"),
	       objfile_name (objfile));
      return NULL;
    }
  *filenamep = std::string (dsym_filename);
  return dsym_bfd;
}
Пример #8
0
char *
fbsd_make_corefile_notes (bfd *obfd, int *note_size)
{
  const struct regcache *regcache = get_current_regcache ();
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  gregset_t gregs;
  fpregset_t fpregs;
  char *note_data = NULL;
  Elf_Internal_Ehdr *i_ehdrp;
  const struct regset *regset;
  size_t size;

  /* Put a "FreeBSD" label in the ELF header.  */
  i_ehdrp = elf_elfheader (obfd);
  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;

  gdb_assert (gdbarch_regset_from_core_section_p (gdbarch));

  size = sizeof gregs;
  regset = gdbarch_regset_from_core_section (gdbarch, ".reg", size);
  gdb_assert (regset && regset->collect_regset);
  regset->collect_regset (regset, regcache, -1, &gregs, size);

  note_data = elfcore_write_prstatus (obfd, note_data, note_size,
				      ptid_get_pid (inferior_ptid),
				      find_stop_signal (), &gregs);

  size = sizeof fpregs;
  regset = gdbarch_regset_from_core_section (gdbarch, ".reg2", size);
  gdb_assert (regset && regset->collect_regset);
  regset->collect_regset (regset, regcache, -1, &fpregs, size);

  note_data = elfcore_write_prfpreg (obfd, note_data, note_size,
				     &fpregs, sizeof (fpregs));

  if (get_exec_file (0))
    {
      const char *fname = lbasename (get_exec_file (0));
      char *psargs = xstrdup (fname);

      if (get_inferior_args ())
	psargs = reconcat (psargs, psargs, " ", get_inferior_args (),
			   (char *) NULL);

      note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
					  fname, psargs);
    }

  make_cleanup (xfree, note_data);
  return note_data;
}
Пример #9
0
static void
verror( int n, va_list ap)
{
	const	char *fn;

	if (ERR_ISSET(n, &msgset))
		return;

	fn = lbasename(curr_pos.p_file);
	(void)printf("%s(%d): ", fn, curr_pos.p_line);
	(void)vprintf(msgs[n], ap);
	(void)printf(" [%d]\n", n);
	nerr++;
}
Пример #10
0
void
lerror(const char *msg, ...)
{
	va_list	ap;
	const	char *fn;

	va_start(ap, msg);
	fn = lbasename(curr_pos.p_file);
	(void)fprintf(stderr, "%s(%d): lint error: ", fn, curr_pos.p_line);
	(void)vfprintf(stderr, msg, ap);
	(void)fprintf(stderr, "\n");
	va_end(ap);
	exit(1);
}
Пример #11
0
static void
gldelf64ltsmip_stat_needed (lang_input_statement_type *s)
{
  struct stat st;
  const char *suffix;
  const char *soname;

  if (global_found)
    return;
  if (s->the_bfd == NULL)
    return;

  if (bfd_stat (s->the_bfd, &st) != 0)
    {
      einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd);
      return;
    }

  if (st.st_dev == global_stat.st_dev
      && st.st_ino == global_stat.st_ino)
    {
      global_found = TRUE;
      return;
    }

  /* We issue a warning if it looks like we are including two
     different versions of the same shared library.  For example,
     there may be a problem if -lc picks up libc.so.6 but some other
     shared library has a DT_NEEDED entry of libc.so.5.  This is a
     heuristic test, and it will only work if the name looks like
     NAME.so.VERSION.  FIXME: Depending on file names is error-prone.
     If we really want to issue warnings about mixing version numbers
     of shared libraries, we need to find a better way.  */

  if (strchr (global_needed->name, '/') != NULL)
    return;
  suffix = strstr (global_needed->name, ".so.");
  if (suffix == NULL)
    return;
  suffix += sizeof ".so." - 1;

  soname = bfd_elf_get_dt_soname (s->the_bfd);
  if (soname == NULL)
    soname = lbasename (s->filename);

  if (strncmp (soname, global_needed->name, suffix - global_needed->name) == 0)
    einfo ("%P: warning: %s, needed by %B, may conflict with %s\n",
	   global_needed->name, global_needed->by, soname);
}
Пример #12
0
void
message(int n, ...)
{
	va_list	ap;
	const	char *fn;

	if (ERR_ISSET(n, &msgset))
		return;

	va_start(ap, n);
	fn = lbasename(curr_pos.p_file);
	(void)printf("%s(%d): ", fn, curr_pos.p_line);
	(void)vprintf(msgs[n], ap);
	(void)printf(" [%d]\n", n);
	va_end(ap);
}
Пример #13
0
static void
gldelf64ltsmip_vercheck (lang_input_statement_type *s)
{
  const char *soname;
  struct bfd_link_needed_list *l;

  if (global_vercheck_failed)
    return;
  if (s->the_bfd == NULL
      || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0)
    return;

  soname = bfd_elf_get_dt_soname (s->the_bfd);
  if (soname == NULL)
    soname = lbasename (bfd_get_filename (s->the_bfd));

  for (l = global_vercheck_needed; l != NULL; l = l->next)
    {
      const char *suffix;

      if (strcmp (soname, l->name) == 0)
	{
	  /* Probably can't happen, but it's an easy check.  */
	  continue;
	}

      if (strchr (l->name, '/') != NULL)
	continue;

      suffix = strstr (l->name, ".so.");
      if (suffix == NULL)
	continue;

      suffix += sizeof ".so." - 1;

      if (strncmp (soname, l->name, suffix - l->name) == 0)
	{
	  /* Here we know that S is a dynamic object FOO.SO.VER1, and
	     the object we are considering needs a dynamic object
	     FOO.SO.VER2, and VER1 and VER2 are different.  This
	     appears to be a version mismatch, so we tell the caller
	     to try a different version of this library.  */
	  global_vercheck_failed = TRUE;
	  return;
	}
    }
}
Пример #14
0
static void
vwarning( int n, va_list ap)
{
	const	char *fn;

	if (ERR_ISSET(n, &msgset))
		return;

	if (nowarn)
		/* this warning is suppressed by a LINTED comment */
		return;

	fn = lbasename(curr_pos.p_file);
	(void)printf("%s(%d): warning: ", fn, curr_pos.p_line);
	(void)vprintf(msgs[n], ap);
	(void)printf(" [%d]\n", n);
	if (wflag)
		nerr++;
}
Пример #15
0
gdb::unique_xmalloc_ptr<char>
gdb_realpath_keepfile (const char *filename)
{
  const char *base_name = lbasename (filename);
  char *dir_name;
  char *result;

  /* Extract the basename of filename, and return immediately
     a copy of filename if it does not contain any directory prefix.  */
  if (base_name == filename)
    return gdb::unique_xmalloc_ptr<char> (xstrdup (filename));

  dir_name = (char *) alloca ((size_t) (base_name - filename + 2));
  /* Allocate enough space to store the dir_name + plus one extra
     character sometimes needed under Windows (see below), and
     then the closing \000 character.  */
  strncpy (dir_name, filename, base_name - filename);
  dir_name[base_name - filename] = '\000';

#ifdef HAVE_DOS_BASED_FILE_SYSTEM
  /* We need to be careful when filename is of the form 'd:foo', which
     is equivalent of d:./foo, which is totally different from d:/foo.  */
  if (strlen (dir_name) == 2 && isalpha (dir_name[0]) && dir_name[1] == ':')
    {
      dir_name[2] = '.';
      dir_name[3] = '\000';
    }
#endif

  /* Canonicalize the directory prefix, and build the resulting
     filename.  If the dirname realpath already contains an ending
     directory separator, avoid doubling it.  */
  gdb::unique_xmalloc_ptr<char> path_storage = gdb_realpath (dir_name);
  const char *real_path = path_storage.get ();
  if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1]))
    result = concat (real_path, base_name, (char *) NULL);
  else
    result = concat (real_path, SLASH_STRING, base_name, (char *) NULL);

  return gdb::unique_xmalloc_ptr<char> (result);
}
Пример #16
0
static char *
fbsd_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
{
  struct regcache *regcache = get_current_regcache ();
  char *note_data;
  Elf_Internal_Ehdr *i_ehdrp;
  struct fbsd_collect_regset_section_cb_data data;

  /* Put a "FreeBSD" label in the ELF header.  */
  i_ehdrp = elf_elfheader (obfd);
  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;

  gdb_assert (gdbarch_iterate_over_regset_sections_p (gdbarch));

  data.regcache = regcache;
  data.obfd = obfd;
  data.note_data = NULL;
  data.note_size = note_size;
  target_fetch_registers (regcache, -1);
  gdbarch_iterate_over_regset_sections (gdbarch,
					fbsd_collect_regset_section_cb,
					&data, regcache);
  note_data = data.note_data;

  if (get_exec_file (0))
    {
      const char *fname = lbasename (get_exec_file (0));
      char *psargs = xstrdup (fname);

      if (get_inferior_args ())
	psargs = reconcat (psargs, psargs, " ", get_inferior_args (),
			   (char *) NULL);

      note_data = elfcore_write_prpsinfo (obfd, note_data, note_size,
					  fname, psargs);
    }

  return note_data;
}
Пример #17
0
static void
handle_pragma_implementation (cpp_reader* /*dfile*/)
{
  tree fname = parse_strconst_pragma ("implementation", 1);
  const char *filename;
  struct impl_files *ifiles = impl_file_chain;

  if (fname == error_mark_node)
    return;

  if (fname == 0)
    {
      if (main_input_filename)
	filename = main_input_filename;
      else
	filename = LOCATION_FILE (input_location);
      filename = lbasename (filename);
    }
  else
    {
      filename = TREE_STRING_POINTER (fname);
      if (cpp_included_before (parse_in, filename, input_location))
	warning (0, "#pragma implementation for %qs appears after "
		 "file is included", filename);
    }

  for (; ifiles; ifiles = ifiles->next)
    {
      if (! filename_cmp (ifiles->filename, filename))
	break;
    }
  if (ifiles == 0)
    {
      ifiles = XNEW (struct impl_files);
      ifiles->filename = xstrdup (filename);
      ifiles->next = impl_file_chain;
      impl_file_chain = ifiles;
    }
Пример #18
0
const char *element_name(region r, const char *path)
/* Returns: Return the "identifier part"
     of path, i.e., remove any directory and extension
     The returned string is allocated in region r.
*/
{
  const char *base, *dot;

  base = lbasename(path);
  dot = strrchr(base, '.');

  if (dot)
    {
      /* Extract id */
      char *copy = rarrayalloc(r, dot - base + 1, char);

      memcpy(copy, base, dot - base);
      copy[dot - base] = '\0';

      return copy;
    }
  else
    return rstrdup(r, base);
Пример #19
0
int
main (int argc, char **argv)
{
  const char *name;
  char **prog_argv = NULL;
  struct bfd *prog_bfd;
  enum sim_stop reason;
  int sigrc = 0;
  int single_step = 0;
  RETSIGTYPE (*prev_sigint) ();

  myname = lbasename (argv[0]);

  /* INTERNAL: When MYNAME is `step', single step the simulator
     instead of allowing it to run free.  The sole purpose of this
     HACK is to allow the sim_resume interface's step argument to be
     tested without having to build/run gdb. */
  if (strlen (myname) > 4 && strcmp (myname - 4, "step") == 0)
    {
      single_step = 1;
    }

  /* Create an instance of the simulator.  */
  default_callback.init (&default_callback);
  sd = sim_open (SIM_OPEN_STANDALONE, &default_callback, NULL, argv);
  if (sd == 0)
    exit (1);
  if (STATE_MAGIC (sd) != SIM_MAGIC_NUMBER)
    {
      fprintf (stderr, "Internal error - bad magic number in simulator struct\n");
      abort ();
    }

  /* We can't set the endianness in the callback structure until
     sim_config is called, which happens in sim_open.  */
  default_callback.target_endian
    = (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
       ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE);

  /* Was there a program to run?  */
  prog_argv = STATE_PROG_ARGV (sd);
  prog_bfd = STATE_PROG_BFD (sd);
  if (prog_argv == NULL || *prog_argv == NULL)
    usage ();

  name = *prog_argv;

  /* For simulators that don't open prog during sim_open() */
  if (prog_bfd == NULL)
    {
      prog_bfd = bfd_openr (name, 0);
      if (prog_bfd == NULL)
	{
	  fprintf (stderr, "%s: can't open \"%s\": %s\n",
		   myname, name, bfd_errmsg (bfd_get_error ()));
	  exit (1);
	}
      if (!bfd_check_format (prog_bfd, bfd_object))
	{
	  fprintf (stderr, "%s: \"%s\" is not an object file: %s\n",
		   myname, name, bfd_errmsg (bfd_get_error ()));
	  exit (1);
	}
    }

  if (STATE_VERBOSE_P (sd))
    printf ("%s %s\n", myname, name);

  /* Load the program into the simulator.  */
  if (sim_load (sd, name, prog_bfd, 0) == SIM_RC_FAIL)
    exit (1);

  /* Prepare the program for execution.  */
#ifdef HAVE_ENVIRON
  sim_create_inferior (sd, prog_bfd, prog_argv, environ);
#else
  sim_create_inferior (sd, prog_bfd, prog_argv, NULL);
#endif

  /* To accommodate relative file paths, chdir to sysroot now.  We
     mustn't do this until BFD has opened the program, else we wouldn't
     find the executable if it has a relative file path.  */
  if (simulator_sysroot[0] != '\0' && chdir (simulator_sysroot) < 0)
    {
      fprintf (stderr, "%s: can't change directory to \"%s\"\n",
	       myname, simulator_sysroot);
      exit (1);
    }

  /* Run/Step the program.  */
  if (single_step)
    {
      do
	{
	  prev_sigint = signal (SIGINT, cntrl_c);
	  sim_resume (sd, 1/*step*/, 0);
	  signal (SIGINT, prev_sigint);
	  sim_stop_reason (sd, &reason, &sigrc);

	  if ((reason == sim_stopped) &&
	      (sigrc == sim_signal_to_host (sd, SIM_SIGINT)))
	    break; /* exit on control-C */
	}
      /* remain on breakpoint or signals in oe mode*/
      while (((reason == sim_signalled) &&
	      (sigrc == sim_signal_to_host (sd, SIM_SIGTRAP))) ||
	     ((reason == sim_stopped) &&
	      (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)));
    }
  else
    {
      do
	{
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
	  struct sigaction sa, osa;
	  sa.sa_handler = cntrl_c;
	  sigemptyset (&sa.sa_mask);
	  sa.sa_flags = 0;
	  sigaction (SIGINT, &sa, &osa);
	  prev_sigint = osa.sa_handler;
#else
	  prev_sigint = signal (SIGINT, cntrl_c);
#endif
	  sim_resume (sd, 0, sigrc);
	  signal (SIGINT, prev_sigint);
	  sim_stop_reason (sd, &reason, &sigrc);

	  if ((reason == sim_stopped) &&
	      (sigrc == sim_signal_to_host (sd, SIM_SIGINT)))
	    break; /* exit on control-C */

	  /* remain on signals in oe mode */
	} while ((reason == sim_stopped) &&
		 (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT));

    }
  /* Print any stats the simulator collected.  */
  if (STATE_VERBOSE_P (sd))
    sim_info (sd, 0);

  /* Shutdown the simulator.  */
  sim_close (sd, 0);

  /* If reason is sim_exited, then sigrc holds the exit code which we want
     to return.  If reason is sim_stopped or sim_signalled, then sigrc holds
     the signal that the simulator received; we want to return that to
     indicate failure.  */

  /* Why did we stop? */
  switch (reason)
    {
    case sim_signalled:
    case sim_stopped:
      if (sigrc != 0)
	fprintf (stderr, "program stopped with signal %d (%s).\n", sigrc,
		 strsignal (sigrc));
      break;

    case sim_exited:
      break;

    default:
      fprintf (stderr, "program in undefined state (%d:%d)\n", reason, sigrc);
      break;

    }

  return sigrc;
}
Пример #20
0
static int
bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
	     const char *function)
{
  int *pcount = (int *) data;

  /* If we don't have any useful information, don't print
     anything.  */
  if (filename == NULL && function == NULL)
    return 0;

  /* Skip functions in diagnostic.c.  */
  if (*pcount == 0
      && filename != NULL
      && strcmp (lbasename (filename), "diagnostic.c") == 0)
    return 0;

  /* Print up to 20 functions.  We could make this a --param, but
     since this is only for debugging just use a constant for now.  */
  if (*pcount >= 20)
    {
      /* Returning a non-zero value stops the backtrace.  */
      return 1;
    }
  ++*pcount;

  char *alc = NULL;
  if (function != NULL)
    {
      char *str = cplus_demangle_v3 (function,
				     (DMGL_VERBOSE | DMGL_ANSI
				      | DMGL_GNU_V3 | DMGL_PARAMS));
      if (str != NULL)
	{
	  alc = str;
	  function = str;
	}

      for (size_t i = 0; i < ARRAY_SIZE (bt_stop); ++i)
	{
	  size_t len = strlen (bt_stop[i]);
	  if (strncmp (function, bt_stop[i], len) == 0
	      && (function[len] == '\0' || function[len] == '('))
	    {
	      if (alc != NULL)
		free (alc);
	      /* Returning a non-zero value stops the backtrace.  */
	      return 1;
	    }
	}
    }

  fprintf (stderr, "0x%lx %s\n\t%s:%d\n",
	   (unsigned long) pc,
	   function == NULL ? "???" : function,
	   filename == NULL ? "???" : filename,
	   lineno);

  if (alc != NULL)
    free (alc);

  return 0;
}
Пример #21
0
static const char *
debug_objfile_name (const struct objfile *objfile)
{
  return lbasename (objfile->original_name);
}
Пример #22
0
static void
dequeue_and_dump (dump_info_p di)
{
  dump_queue_p dq;
  splay_tree_node stn;
  dump_node_info_p dni;
  tree t;
  unsigned int index;
  enum tree_code code;
  enum tree_code_class code_class;
  const char* code_name;

  /* Get the next node from the queue.  */
  dq = di->queue;
  stn = dq->node;
  t = (tree) stn->key;
  dni = (dump_node_info_p) stn->value;
  index = dni->index;

  /* Remove the node from the queue, and put it on the free list.  */
  di->queue = dq->next;
  if (!di->queue)
    di->queue_end = 0;
  dq->next = di->free_list;
  di->free_list = dq;

  /* Print the node index.  */
  dump_index (di, index);
  /* And the type of node this is.  */
  if (dni->binfo_p)
    code_name = "binfo";
  else
    code_name = tree_code_name[(int) TREE_CODE (t)];
  fprintf (di->stream, "%-16s ", code_name);
  di->column = 25;

  /* Figure out what kind of node this is.  */
  code = TREE_CODE (t);
  code_class = TREE_CODE_CLASS (code);

  /* Although BINFOs are TREE_VECs, we dump them specially so as to be
     more informative.  */
  if (dni->binfo_p)
    {
      unsigned ix;
      tree base;
      VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t);

      dump_child ("type", BINFO_TYPE (t));

      if (BINFO_VIRTUAL_P (t))
	dump_string_field (di, "spec", "virt");

      dump_int (di, "bases", BINFO_N_BASE_BINFOS (t));
      for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++)
	{
	  tree access = (accesses ? VEC_index (tree, accesses, ix)
			 : access_public_node);
	  const char *string = NULL;

	  if (access == access_public_node)
	    string = "pub";
	  else if (access == access_protected_node)
	    string = "prot";
	  else if (access == access_private_node)
	    string = "priv";
	  else
	    gcc_unreachable ();

	  dump_string_field (di, "accs", string);
	  queue_and_dump_index (di, "binf", base, DUMP_BINFO);
	}

      goto done;
    }

  /* We can knock off a bunch of expression nodes in exactly the same
     way.  */
  if (IS_EXPR_CODE_CLASS (code_class))
    {
      /* If we're dumping children, dump them now.  */
      queue_and_dump_type (di, t);

      switch (code_class)
	{
	case tcc_unary:
	  dump_child ("op 0", TREE_OPERAND (t, 0));
	  break;

	case tcc_binary:
	case tcc_comparison:
	  dump_child ("op 0", TREE_OPERAND (t, 0));
	  dump_child ("op 1", TREE_OPERAND (t, 1));
	  break;

	case tcc_expression:
	case tcc_reference:
	case tcc_statement:
	case tcc_vl_exp:
	  /* These nodes are handled explicitly below.  */
	  break;

	default:
	  gcc_unreachable ();
	}
    }
  else if (DECL_P (t))
    {
      expanded_location xloc;
      /* All declarations have names.  */
      if (DECL_NAME (t))
	dump_child ("name", DECL_NAME (t));
      if (DECL_ASSEMBLER_NAME_SET_P (t)
	  && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
	dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
      if (DECL_ABSTRACT_ORIGIN (t))
        dump_child ("orig", DECL_ABSTRACT_ORIGIN (t));
      /* And types.  */
      queue_and_dump_type (di, t);
      dump_child ("scpe", DECL_CONTEXT (t));
      /* And a source position.  */
      xloc = expand_location (DECL_SOURCE_LOCATION (t));
      if (xloc.file)
	{
	  const char *filename = lbasename (xloc.file);

	  dump_maybe_newline (di);
	  fprintf (di->stream, "srcp: %s:%-6d ", filename,
		   xloc.line);
	  di->column += 6 + strlen (filename) + 8;
	}
      /* And any declaration can be compiler-generated.  */
      if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON)
	  && DECL_ARTIFICIAL (t))
	dump_string_field (di, "note", "artificial");
      if (DECL_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
	dump_child ("chain", DECL_CHAIN (t));
    }
  else if (code_class == tcc_type)
    {
      /* All types have qualifiers.  */
      int quals = lang_hooks.tree_dump.type_quals (t);

      if (quals != TYPE_UNQUALIFIED)
	{
	  fprintf (di->stream, "qual: %c%c%c     ",
		   (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
		   (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
		   (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
	  di->column += 14;
	}

      /* All types have associated declarations.  */
      dump_child ("name", TYPE_NAME (t));

      /* All types have a main variant.  */
      if (TYPE_MAIN_VARIANT (t) != t)
	dump_child ("unql", TYPE_MAIN_VARIANT (t));

      /* And sizes.  */
      dump_child ("size", TYPE_SIZE (t));

      /* All types have alignments.  */
      dump_int (di, "algn", TYPE_ALIGN (t));
    }
  else if (code_class == tcc_constant)
    /* All constants can have types.  */
    queue_and_dump_type (di, t);

  /* Give the language-specific code a chance to print something.  If
     it's completely taken care of things, don't bother printing
     anything more ourselves.  */
  if (lang_hooks.tree_dump.dump_tree (di, t))
    goto done;

  /* Now handle the various kinds of nodes.  */
  switch (code)
    {
      int i;

    case IDENTIFIER_NODE:
      dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
      dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
      break;

    case TREE_LIST:
      dump_child ("purp", TREE_PURPOSE (t));
      dump_child ("valu", TREE_VALUE (t));
      dump_child ("chan", TREE_CHAIN (t));
      break;

    case STATEMENT_LIST:
      {
	tree_stmt_iterator it;
	for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
	  {
	    char buffer[32];
	    sprintf (buffer, "%u", i);
	    dump_child (buffer, tsi_stmt (it));
	  }
      }
      break;

    case TREE_VEC:
      dump_int (di, "lngt", TREE_VEC_LENGTH (t));
      for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
	{
	  char buffer[32];
	  sprintf (buffer, "%u", i);
	  dump_child (buffer, TREE_VEC_ELT (t, i));
	}
      break;

    case INTEGER_TYPE:
    case ENUMERAL_TYPE:
      dump_int (di, "prec", TYPE_PRECISION (t));
      dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
      dump_child ("min", TYPE_MIN_VALUE (t));
      dump_child ("max", TYPE_MAX_VALUE (t));

      if (code == ENUMERAL_TYPE)
	dump_child ("csts", TYPE_VALUES (t));
      break;

    case REAL_TYPE:
      dump_int (di, "prec", TYPE_PRECISION (t));
      break;

    case FIXED_POINT_TYPE:
      dump_int (di, "prec", TYPE_PRECISION (t));
      dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
      dump_string_field (di, "saturating",
			 TYPE_SATURATING (t) ? "saturating": "non-saturating");
      break;

    case POINTER_TYPE:
      dump_child ("ptd", TREE_TYPE (t));
      break;

    case REFERENCE_TYPE:
      dump_child ("refd", TREE_TYPE (t));
      break;

    case METHOD_TYPE:
      dump_child ("clas", TYPE_METHOD_BASETYPE (t));
      /* Fall through.  */

    case FUNCTION_TYPE:
      dump_child ("retn", TREE_TYPE (t));
      dump_child ("prms", TYPE_ARG_TYPES (t));
      break;

    case ARRAY_TYPE:
      dump_child ("elts", TREE_TYPE (t));
      dump_child ("domn", TYPE_DOMAIN (t));
      break;

    case RECORD_TYPE:
    case UNION_TYPE:
      if (TREE_CODE (t) == RECORD_TYPE)
	dump_string_field (di, "tag", "struct");
      else
	dump_string_field (di, "tag", "union");

      dump_child ("flds", TYPE_FIELDS (t));
      dump_child ("fncs", TYPE_METHODS (t));
      queue_and_dump_index (di, "binf", TYPE_BINFO (t),
			    DUMP_BINFO);
      break;

    case CONST_DECL:
      dump_child ("cnst", DECL_INITIAL (t));
      break;

    case DEBUG_EXPR_DECL:
      dump_int (di, "-uid", DEBUG_TEMP_UID (t));
      /* Fall through.  */

    case VAR_DECL:
    case PARM_DECL:
    case FIELD_DECL:
    case RESULT_DECL:
      if (TREE_CODE (t) == PARM_DECL)
	dump_child ("argt", DECL_ARG_TYPE (t));
      else
	dump_child ("init", DECL_INITIAL (t));
      dump_child ("size", DECL_SIZE (t));
      dump_int (di, "algn", DECL_ALIGN (t));

      if (TREE_CODE (t) == FIELD_DECL)
	{
	  if (DECL_FIELD_OFFSET (t))
	    dump_child ("bpos", bit_position (t));
	}
      else if (TREE_CODE (t) == VAR_DECL
	       || TREE_CODE (t) == PARM_DECL)
	{
	  dump_int (di, "used", TREE_USED (t));
	  if (DECL_REGISTER (t))
	    dump_string_field (di, "spec", "register");
	}
      break;

    case FUNCTION_DECL:
      dump_child ("args", DECL_ARGUMENTS (t));
      if (DECL_EXTERNAL (t))
	dump_string_field (di, "body", "undefined");
      if (TREE_PUBLIC (t))
	dump_string_field (di, "link", "extern");
      else
	dump_string_field (di, "link", "static");
      if (DECL_SAVED_TREE (t) && !dump_flag (di, TDF_SLIM, t))
	dump_child ("body", DECL_SAVED_TREE (t));
      break;

    case INTEGER_CST:
      if (TREE_INT_CST_HIGH (t))
	dump_int (di, "high", TREE_INT_CST_HIGH (t));
      dump_int (di, "low", TREE_INT_CST_LOW (t));
      break;

    case STRING_CST:
      fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
      dump_int (di, "lngt", TREE_STRING_LENGTH (t));
      break;

    case REAL_CST:
      dump_real (di, "valu", TREE_REAL_CST_PTR (t));
      break;

    case FIXED_CST:
      dump_fixed (di, "valu", TREE_FIXED_CST_PTR (t));
      break;

    case TRUTH_NOT_EXPR:
    case ADDR_EXPR:
    case INDIRECT_REF:
    case CLEANUP_POINT_EXPR:
    case SAVE_EXPR:
    case REALPART_EXPR:
    case IMAGPART_EXPR:
      /* These nodes are unary, but do not have code class `1'.  */
      dump_child ("op 0", TREE_OPERAND (t, 0));
      break;

    case TRUTH_ANDIF_EXPR:
    case TRUTH_ORIF_EXPR:
    case INIT_EXPR:
    case MODIFY_EXPR:
    case COMPOUND_EXPR:
    case PREDECREMENT_EXPR:
    case PREINCREMENT_EXPR:
    case POSTDECREMENT_EXPR:
    case POSTINCREMENT_EXPR:
      /* These nodes are binary, but do not have code class `2'.  */
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      break;

    case COMPONENT_REF:
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      dump_child ("op 2", TREE_OPERAND (t, 2));
      break;

    case ARRAY_REF:
    case ARRAY_RANGE_REF:
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      dump_child ("op 2", TREE_OPERAND (t, 2));
      dump_child ("op 3", TREE_OPERAND (t, 3));
      break;

    case COND_EXPR:
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      dump_child ("op 2", TREE_OPERAND (t, 2));
      break;

    case TRY_FINALLY_EXPR:
      dump_child ("op 0", TREE_OPERAND (t, 0));
      dump_child ("op 1", TREE_OPERAND (t, 1));
      break;

    case CALL_EXPR:
      {
	int i = 0;
	tree arg;
	call_expr_arg_iterator iter;
	dump_child ("fn", CALL_EXPR_FN (t));
	FOR_EACH_CALL_EXPR_ARG (arg, iter, t)
	  {
	    char buffer[32];
	    sprintf (buffer, "%u", i);
	    dump_child (buffer, arg);
	    i++;
	  }
      }
      break;

    case CONSTRUCTOR:
      {
	unsigned HOST_WIDE_INT cnt;
	tree index, value;
	dump_int (di, "lngt", VEC_length (constructor_elt,
					  CONSTRUCTOR_ELTS (t)));
	FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value)
	  {
	    dump_child ("idx", index);
	    dump_child ("val", value);
	  }
      }
Пример #23
0
struct bound_minimal_symbol
lookup_minimal_symbol (const char *name, const char *sfile,
		       struct objfile *objf)
{
  struct objfile *objfile;
  found_minimal_symbols found;

  unsigned int mangled_hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;

  auto *mangled_cmp
    = (case_sensitivity == case_sensitive_on
       ? strcmp
       : strcasecmp);

  if (sfile != NULL)
    sfile = lbasename (sfile);

  lookup_name_info lookup_name (name, symbol_name_match_type::FULL);

  for (objfile = object_files;
       objfile != NULL && found.external_symbol.minsym == NULL;
       objfile = objfile->next)
    {
      if (objf == NULL || objf == objfile
	  || objf == objfile->separate_debug_objfile_backlink)
	{
	  if (symbol_lookup_debug)
	    {
	      fprintf_unfiltered (gdb_stdlog,
				  "lookup_minimal_symbol (%s, %s, %s)\n",
				  name, sfile != NULL ? sfile : "NULL",
				  objfile_debug_name (objfile));
	    }

	  /* Do two passes: the first over the ordinary hash table,
	     and the second over the demangled hash table.  */
	  lookup_minimal_symbol_mangled (name, sfile, objfile,
					 objfile->per_bfd->msymbol_hash,
					 mangled_hash, mangled_cmp, found);

	  /* If not found, try the demangled hash table.  */
	  if (found.external_symbol.minsym == NULL)
	    {
	      /* Once for each language in the demangled hash names
		 table (usually just zero or one languages).  */
	      for (auto lang : objfile->per_bfd->demangled_hash_languages)
		{
		  unsigned int hash
		    = (lookup_name.search_name_hash (lang)
		       % MINIMAL_SYMBOL_HASH_SIZE);

		  symbol_name_matcher_ftype *match
		    = get_symbol_name_matcher (language_def (lang),
					       lookup_name);
		  struct minimal_symbol **msymbol_demangled_hash
		    = objfile->per_bfd->msymbol_demangled_hash;

		  lookup_minimal_symbol_demangled (lookup_name, sfile, objfile,
						   msymbol_demangled_hash,
						   hash, match, found);

		  if (found.external_symbol.minsym != NULL)
		    break;
		}
	    }
	}
    }

  /* External symbols are best.  */
  if (found.external_symbol.minsym != NULL)
    {
      if (symbol_lookup_debug)
	{
	  minimal_symbol *minsym = found.external_symbol.minsym;

	  fprintf_unfiltered (gdb_stdlog,
			      "lookup_minimal_symbol (...) = %s (external)\n",
			      host_address_to_string (minsym));
	}
      return found.external_symbol;
    }

  /* File-local symbols are next best.  */
  if (found.file_symbol.minsym != NULL)
    {
      if (symbol_lookup_debug)
	{
	  minimal_symbol *minsym = found.file_symbol.minsym;

	  fprintf_unfiltered (gdb_stdlog,
			      "lookup_minimal_symbol (...) = %s (file-local)\n",
			      host_address_to_string (minsym));
	}
      return found.file_symbol;
    }

  /* Symbols for shared library trampolines are next best.  */
  if (found.trampoline_symbol.minsym != NULL)
    {
      if (symbol_lookup_debug)
	{
	  minimal_symbol *minsym = found.trampoline_symbol.minsym;

	  fprintf_unfiltered (gdb_stdlog,
			      "lookup_minimal_symbol (...) = %s (trampoline)\n",
			      host_address_to_string (minsym));
	}

      return found.trampoline_symbol;
    }

  /* Not found.  */
  if (symbol_lookup_debug)
    fprintf_unfiltered (gdb_stdlog, "lookup_minimal_symbol (...) = NULL\n");
  return {};
}
Пример #24
0
/* Return the portion of PATHNAME that should be output when listing
   possible completions.  If we are hacking filename completion, we
   are only interested in the basename, the portion following the
   final slash.  Otherwise, we return what we were passed.

   Comes from readline/complete.c.  */
static const char *
printable_part (const char *pathname)
{
  return rl_filename_completion_desired ? lbasename (pathname) : pathname;
}
Пример #25
0
static unsigned int
get_filenum (const char *filename, unsigned int num)
{
  static unsigned int last_used, last_used_dir_len;
  const char *file;
  size_t dir_len;
  unsigned int i, dir;

  if (num == 0 && last_used)
    {
      if (! files[last_used].dir
	  && filename_cmp (filename, files[last_used].filename) == 0)
	return last_used;
      if (files[last_used].dir
	  && filename_ncmp (filename, dirs[files[last_used].dir],
			    last_used_dir_len) == 0
	  && IS_DIR_SEPARATOR (filename [last_used_dir_len])
	  && filename_cmp (filename + last_used_dir_len + 1,
			   files[last_used].filename) == 0)
	return last_used;
    }

  file = lbasename (filename);
  /* Don't make empty string from / or A: from A:/ .  */
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
  if (file <= filename + 3)
    file = filename;
#else
  if (file == filename + 1)
    file = filename;
#endif
  dir_len = file - filename;

  dir = 0;
  if (dir_len)
    {
#ifndef DWARF2_DIR_SHOULD_END_WITH_SEPARATOR
      --dir_len;
#endif
      for (dir = 1; dir < dirs_in_use; ++dir)
	if (filename_ncmp (filename, dirs[dir], dir_len) == 0
	    && dirs[dir][dir_len] == '\0')
	  break;

      if (dir >= dirs_in_use)
	{
	  if (dir >= dirs_allocated)
	    {
	      dirs_allocated = dir + 32;
	      dirs = (char **)
		     xrealloc (dirs, (dir + 32) * sizeof (const char *));
	    }

	  dirs[dir] = (char *) xmalloc (dir_len + 1);
	  memcpy (dirs[dir], filename, dir_len);
	  dirs[dir][dir_len] = '\0';
	  dirs_in_use = dir + 1;
	}
    }

  if (num == 0)
    {
      for (i = 1; i < files_in_use; ++i)
	if (files[i].dir == dir
	    && files[i].filename
	    && filename_cmp (file, files[i].filename) == 0)
	  {
	    last_used = i;
	    last_used_dir_len = dir_len;
	    return i;
	  }
    }
  else
    i = num;

  if (i >= files_allocated)
    {
      unsigned int old = files_allocated;

      files_allocated = i + 32;
      files = (struct file_entry *)
	xrealloc (files, (i + 32) * sizeof (struct file_entry));

      memset (files + old, 0, (i + 32 - old) * sizeof (struct file_entry));
    }

  files[i].filename = num ? file : xstrdup (file);
  files[i].dir = dir;
  if (files_in_use < i + 1)
    files_in_use = i + 1;
  last_used = i;
  last_used_dir_len = dir_len;

  return i;
}
Пример #26
0
static bfd_boolean
gldelf64ltsmip_try_needed (const char *name, int force)
{
  bfd *abfd;
  const char *soname;

  abfd = bfd_openr (name, bfd_get_target (output_bfd));
  if (abfd == NULL)
    return FALSE;
  if (! bfd_check_format (abfd, bfd_object))
    {
      bfd_close (abfd);
      return FALSE;
    }
  if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0)
    {
      bfd_close (abfd);
      return FALSE;
    }

  /* For DT_NEEDED, they have to match.  */
  if (abfd->xvec != output_bfd->xvec)
    {
      bfd_close (abfd);
      return FALSE;
    }

  /* Check whether this object would include any conflicting library
     versions.  If FORCE is set, then we skip this check; we use this
     the second time around, if we couldn't find any compatible
     instance of the shared library.  */

  if (! force)
    {
      struct bfd_link_needed_list *needed;

      if (! bfd_elf_get_bfd_needed_list (abfd, &needed))
	einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd);

      if (needed != NULL)
	{
	  global_vercheck_needed = needed;
	  global_vercheck_failed = FALSE;
	  lang_for_each_input_file (gldelf64ltsmip_vercheck);
	  if (global_vercheck_failed)
	    {
	      bfd_close (abfd);
	      /* Return FALSE to force the caller to move on to try
		 another file on the search path.  */
	      return FALSE;
	    }

	  /* But wait!  It gets much worse.  On Linux, if a shared
	     library does not use libc at all, we are supposed to skip
	     it the first time around in case we encounter a shared
	     library later on with the same name which does use the
	     version of libc that we want.  This is much too horrible
	     to use on any system other than Linux.  */

	  {
	    struct bfd_link_needed_list *l;

	    for (l = needed; l != NULL; l = l->next)
	      if (strncmp (l->name, "libc.so", 7) == 0)
		break;
	    if (l == NULL)
	      {
		bfd_close (abfd);
		return FALSE;
	      }
	  }

	}
    }

  /* We've found a dynamic object matching the DT_NEEDED entry.  */

  /* We have already checked that there is no other input file of the
     same name.  We must now check again that we are not including the
     same file twice.  We need to do this because on many systems
     libc.so is a symlink to, e.g., libc.so.1.  The SONAME entry will
     reference libc.so.1.  If we have already included libc.so, we
     don't want to include libc.so.1 if they are the same file, and we
     can only check that using stat.  */

  if (bfd_stat (abfd, &global_stat) != 0)
    einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd);

  /* First strip off everything before the last '/'.  */
  soname = lbasename (abfd->filename);

  if (trace_file_tries)
    info_msg (_("found %s at %s\n"), soname, name);

  global_found = FALSE;
  lang_for_each_input_file (gldelf64ltsmip_stat_needed);
  if (global_found)
    {
      /* Return TRUE to indicate that we found the file, even though
	 we aren't going to do anything with it.  */
      return TRUE;
    }

  /* Tell the ELF backend that we don't want the output file to have a
     DT_NEEDED entry for this file.  */
  bfd_elf_set_dt_needed_name (abfd, "");

  /* Tell the ELF backend that the output file needs a DT_NEEDED
     entry for this file if it is used to resolve the reference in
     a regular object.  */
  bfd_elf_set_dt_needed_soname (abfd, soname);

  /* Add this file into the symbol table.  */
  if (! bfd_link_add_symbols (abfd, &link_info))
    einfo ("%F%B: could not read symbols: %E\n", abfd);

  return TRUE;
}
Пример #27
0
void
lang_specific_driver (cl_decoded_option **in_decoded_options,
		      unsigned int *in_decoded_options_count,
		      int *in_added_libraries)
{
  int i, j;

  /* If nonzero, the user gave us the `-p' or `-pg' flag.  */
  int saw_profile_flag = 0;

  /* Used by -debuglib */
  int saw_debug_flag = 0;

  /* What do with libgphobos:
     -1 means we should not link in libgphobos
     0  means we should link in libgphobos if it is needed
     1  means libgphobos is needed and should be linked in.
     2  means libgphobos is needed and should be linked statically.  */
  int library = 0;

  /* If nonzero, use the standard D runtime library when linking with
     standard libraries. */
  int phobos = 1;

  /* The number of arguments being added to what's in argv, other than
     libraries.  We use this to track the number of times we've inserted
     -xd/-xnone.  */
  int added = 0;

  /* The new argument list will be contained in this.  */
  cl_decoded_option *new_decoded_options;

  /* "-lm" or "-lmath" if it appears on the command line.  */
  const cl_decoded_option *saw_math = 0;

  /* "-lpthread" if it appears on the command line.  */
  const cl_decoded_option *saw_thread = 0;

  /* "-lrt" if it appears on the command line.  */
  const cl_decoded_option *saw_time = 0;

  /* "-lc" if it appears on the command line.  */
  const cl_decoded_option *saw_libc = 0;

  /* "-lstdc++" if it appears on the command line.  */
  const cl_decoded_option *saw_libcxx = 0;

  /* An array used to flag each argument that needs a bit set for
     DSOURCE, MATHLIB, WITHTHREAD, WITHLIBC or WITHLIBCXX.  */
  int *args;

  /* Whether we need the C++ STD library.  */
  int need_stdcxx = 0;

  /* By default, we throw on the math library if we have one.  */
  int need_math = (MATH_LIBRARY[0] != '\0');

  /* Whether we need the thread library.  */
  int need_thread = (THREAD_LIBRARY[0] != '\0');

  /* By default, we throw on the time library if we have one.  */
  int need_time = (TIME_LIBRARY[0] != '\0');

  /* True if we saw -static. */
  int static_link = 0;

  /* True if we should add -shared-libgcc to the command-line.  */
  int shared_libgcc = 1;

  /* The total number of arguments with the new stuff.  */
  int argc;

  /* The argument list.  */
  cl_decoded_option *decoded_options;

  /* What default library to use instead of phobos */
  const char *defaultlib = NULL;

  /* What debug library to use instead of phobos */
  const char *debuglib = NULL;

  /* The number of libraries added in.  */
  int added_libraries;

  /* The total number of arguments with the new stuff.  */
  int num_args = 1;

  /* "-fonly" if it appears on the command line.  */
  const char *only_source_option = 0;

  /* Whether the -o option was used.  */
  int saw_opt_o = 0;

  /* The first input file with an extension of .d.  */
  const char *first_d_file = NULL;

  argc = *in_decoded_options_count;
  decoded_options = *in_decoded_options;
  added_libraries = *in_added_libraries;

  args = XCNEWVEC (int, argc);

  for (i = 1; i < argc; i++)
    {
      const char *arg = decoded_options[i].arg;

      switch (decoded_options[i].opt_index)
	{
	case OPT_nostdlib:
	case OPT_nodefaultlibs:
	  library = -1;
	  break;

	case OPT_nophoboslib:
	  added = 1; // force argument rebuild
	  phobos = 0;
	  args[i] |= SKIPOPT;
	  break;

	case OPT_defaultlib_:
	  added = 1;
	  phobos = 0;
	  args[i] |= SKIPOPT;
	  if (defaultlib != NULL)
	    free (CONST_CAST (char *, defaultlib));
	  if (arg == NULL)
	    error ("missing argument to 'defaultlib=' option");
	  else
	    {
	      defaultlib = XNEWVEC (char, strlen (arg));
	      strcpy (CONST_CAST (char *, defaultlib), arg);
	    }
	  break;

	case OPT_debuglib_:
	  added = 1;
	  phobos = 0;
	  args[i] |= SKIPOPT;
	  if (debuglib != NULL)
	    free (CONST_CAST (char *, debuglib));
	  if (arg == NULL)
	    error ("missing argument to 'debuglib=' option");
	  else
	    {
	      debuglib = XNEWVEC (char, strlen (arg));
	      strcpy (CONST_CAST (char *, debuglib), arg);
	    }
	  break;

	case OPT_l:
	  if ((strcmp (arg, LIBSTDCXX) == 0)
	      || (strcmp (arg, LIBSTDCXX_PROFILE) == 0))
	    {
	      args[i] |= WITHLIBCXX;
	      need_stdcxx = 0;
	    }
	  else if ((strcmp (arg, MATH_LIBRARY) == 0)
		   || (strcmp (arg, MATH_LIBRARY_PROFILE) == 0))
	    {
	      args[i] |= MATHLIB;
	      need_math = 0;
	    }
	  else if (strcmp (arg, THREAD_LIBRARY) == 0)
	    {
	      args[i] |= WITHTHREAD;
	      need_thread = 0;
	    }
	  else if (strcmp (arg, TIME_LIBRARY) == 0)
	    {
	      args[i] |= TIMELIB;
	      need_time = 0;
	    }
	  else if (strcmp (arg, "c") == 0)
	    args[i] |= WITHLIBC;
	  else
	    /* Unrecognized libraries (e.g. -ltango) may require libphobos.  */
	    library = (library == 0) ? 1 : library;
	  break;

	case OPT_pg:
	case OPT_p:
	  saw_profile_flag++;
	  break;

	case OPT_g:
	  saw_debug_flag = 1;

	case OPT_v:
	  /* If they only gave us `-v', don't try to link in libphobos.  */
	  if (argc == 2)
	    library = 0;
	  break;

	case OPT_x:
	  if (library == 0
	      && (strcmp (arg, "d") == 0))
	    library = 1;
	  break;

	case OPT_Xlinker:
	case OPT_Wl_:
	  /* Arguments that go directly to the linker might be .o files
	     or something, and so might cause libphobos to be needed.  */
	  if (library == 0)
	    library = 1;
	  break;

	case OPT_c:
	case OPT_S:
	case OPT_E:
	case OPT_M:
	case OPT_MM:
	case OPT_fsyntax_only:
	  /* Don't specify libaries if we won't link, since that would
	     cause a warning.  */
	  library = -1;
	  break;

	case OPT_o:
	  saw_opt_o = 1;
	  break;

	case OPT_static:
	  static_link = 1;
	  break;

	case OPT_static_libgcc:
	  shared_libgcc = 0;
	  break;

	case OPT_static_libphobos:
	  library = library >= 0 ? 2 : library;
	  args[i] |= SKIPOPT;
	  break;

	case OPT_fonly_:
	  args[i] |= SKIPOPT;
	  only_source_option = decoded_options[i].orig_option_with_args_text;

	  if (arg != NULL)
	    {
	      int len = strlen (only_source_option);
	      if (len <= 2 || only_source_option[len-1] != 'd'
		  || only_source_option[len-2] != '.')
		only_source_option = concat (only_source_option, ".d", NULL);
	    }
	  break;

	case OPT_SPECIAL_input_file:
	    {
	      int len;

	      if (arg[0] == '\0' || arg[1] == '\0')
		continue;

	      len = strlen (arg);
	      /* Record that this is a D source file.  */
	      if (len <= 2 || strcmp (arg + len - 2, ".d") == 0)
		{
		  if (first_d_file == NULL)
		    first_d_file = arg;

		  args[i] |= DSOURCE;
		}

	      /* If we don't know that this is a interface file, we might
		 need to be link against libphobos library.  */
	      if (library == 0)
		{
		  if (len <= 3 || strcmp (arg + len - 3, ".di") != 0)
		    library = 1;
		}

	      /* If this is a C++ source file, we'll need to link
		 against libstdc++ library.  */
	      if ((len <= 3 || strcmp (arg + len - 3, ".cc") == 0)
		  || (len <= 4 || strcmp (arg + len - 4, ".cpp") == 0)
		  || (len <= 4 || strcmp (arg + len - 4, ".c++") == 0))
		need_stdcxx = 1;

	      break;
	    }
	}
    }

  /* If we know we don't have to do anything, bail now.  */
  if (!added && library <= 0 && !only_source_option)
    {
      free (args);
      return;
    }

  /* There's no point adding -shared-libgcc if we don't have a shared
     libgcc.  */
#ifndef ENABLE_SHARED_LIBGCC
  shared_libgcc = 0;
#endif

  /* Make sure to have room for the trailing NULL argument.  */
  /* There is one extra argument added here for the runtime
     library: -lgphobos.  The -pthread argument is added by
     setting need_thread. */
  num_args = argc + added + need_math + shared_libgcc + (library > 0) * 5 + 2;
  new_decoded_options = XNEWVEC (cl_decoded_option, num_args);

  i = 0;
  j = 0;

  /* Copy the 0th argument, i.e., the name of the program itself.  */
  new_decoded_options[j++] = decoded_options[i++];

  /* NOTE: We start at 1 now, not 0.  */
  while (i < argc)
    {
      if (args[i] & SKIPOPT)
	{
	  ++i;
	  continue;
	}

      new_decoded_options[j] = decoded_options[i];

      /* Make sure -lphobos is before the math library, since libphobos
	 itself uses those math routines.  */
      if (!saw_math && (args[i] & MATHLIB) && library > 0)
	{
	  --j;
	  saw_math = &decoded_options[i];
	}

      if (!saw_thread && (args[i] & WITHTHREAD) && library > 0)
	{
	  --j;
	  saw_thread = &decoded_options[i];
	}

      if (!saw_time && (args[i] & TIMELIB) && library > 0)
	{
	  --j;
	  saw_time = &decoded_options[i];
	}

      if (!saw_libc && (args[i] & WITHLIBC) && library > 0)
	{
	  --j;
	  saw_libc = &decoded_options[i];
	}

      if (!saw_libcxx && (args[i] & WITHLIBCXX) && library > 0)
	{
	  --j;
	  saw_libcxx = &decoded_options[i];
	}

      if (args[i] & DSOURCE)
	{
	  if (only_source_option)
	    --j;
	}

      i++;
      j++;
    }

  if (only_source_option)
    {
      const char *only_source_arg = only_source_option + 7;
      generate_option (OPT_fonly_, only_source_arg, 1, CL_DRIVER,
		       &new_decoded_options[j]);
      j++;

      generate_option_input_file (only_source_arg,
				  &new_decoded_options[j++]);
    }

  /* If we are not linking, add a -o option.  This is because we need
     the driver to pass all .d files to cc1d.  Without a -o option the
     driver will invoke cc1d separately for each input file.  */
  if (library < 0 && first_d_file != NULL && !saw_opt_o)
    {
      const char *base;
      int baselen;
      int alen;
      char *out;

      base = lbasename (first_d_file);
      baselen = strlen (base) - 2;
      alen = baselen + 3;
      out = XNEWVEC (char, alen);
      memcpy (out, base, baselen);
      /* The driver will convert .o to some other suffix if appropriate.  */
      out[baselen] = '.';
      out[baselen + 1] = 'o';
      out[baselen + 2] = '\0';
      generate_option (OPT_o, out, 1, CL_DRIVER,
		       &new_decoded_options[j]);
      j++;
    }

  /* Add `-lgphobos' if we haven't already done so.  */
  if (library > 0 && phobos)
    {
#ifdef HAVE_LD_STATIC_DYNAMIC
      if (library > 1 && !static_link)
	{
	  generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER,
			   &new_decoded_options[j]);
	  j++;
	}
#endif

      generate_option (OPT_l, saw_profile_flag ? LIBPHOBOS_PROFILE : LIBPHOBOS, 1,
		       CL_DRIVER, &new_decoded_options[j]);
      added_libraries++;
      j++;
      generate_option (OPT_l, saw_profile_flag ? LIBDRUNTIME_PROFILE : LIBDRUNTIME, 1,
		       CL_DRIVER, &new_decoded_options[j]);
      added_libraries++;
      j++;

#ifdef HAVE_LD_STATIC_DYNAMIC
      if (library > 1 && !static_link)
	{
	  generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER,
			   &new_decoded_options[j]);
	  j++;
	}
#endif
    }
  else if (saw_debug_flag && debuglib)
    {
      generate_option (OPT_l, debuglib, 1, CL_DRIVER,
		       &new_decoded_options[j++]);
      added_libraries++;
    }
  else if (defaultlib)
    {
      generate_option (OPT_l, defaultlib, 1, CL_DRIVER,
		       &new_decoded_options[j++]);
      added_libraries++;
    }

  if (saw_libcxx)
    new_decoded_options[j++] = *saw_libcxx;
  else if (library > 0 && need_stdcxx)
    {
      generate_option (OPT_l,
		       (saw_profile_flag
			? LIBSTDCXX_PROFILE
			: LIBSTDCXX),
		       1, CL_DRIVER, &new_decoded_options[j++]);
      added_libraries++;
    }

  if (saw_math)
    new_decoded_options[j++] = *saw_math;
  else if (library > 0 && need_math)
    {
      generate_option (OPT_l,
		       (saw_profile_flag
			? MATH_LIBRARY_PROFILE
			: MATH_LIBRARY),
		       1, CL_DRIVER, &new_decoded_options[j++]);
      added_libraries++;
    }

  if (saw_thread)
    new_decoded_options[j++] = *saw_thread;
  else if (library > 0 && need_thread)
    {
      generate_option (OPT_l, THREAD_LIBRARY, 1, CL_DRIVER,
		       &new_decoded_options[j++]);
      added_libraries++;
    }

  if (saw_time)
    new_decoded_options[j++] = *saw_time;
  else if (library > 0 && need_time)
    {
      generate_option (OPT_l, TIME_LIBRARY, 1, CL_DRIVER,
		       &new_decoded_options[j++]);
      added_libraries++;
    }

  if (saw_libc)
    new_decoded_options[j++] = *saw_libc;

  if (shared_libgcc && !static_link)
    {
      generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER,
		       &new_decoded_options[j++]);
    }

  *in_decoded_options_count = j;
  *in_decoded_options = new_decoded_options;
  *in_added_libraries = added_libraries;
}
Пример #28
0
static bfd_boolean
gldelf64ltsmip_open_dynamic_archive
  (const char *arch, search_dirs_type *search, lang_input_statement_type *entry)
{
  const char *filename;
  char *string;

  if (! entry->is_archive)
    return FALSE;

  filename = entry->filename;

  /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION
     is defined, but it does not seem worth the headache to optimize
     away those two bytes of space.  */
  string = (char *) xmalloc (strlen (search->name)
			     + strlen (filename)
			     + strlen (arch)
#ifdef EXTRA_SHLIB_EXTENSION
			     + strlen (EXTRA_SHLIB_EXTENSION)
#endif
			     + sizeof "/lib.so");

  sprintf (string, "%s/lib%s%s.so", search->name, filename, arch);

#ifdef EXTRA_SHLIB_EXTENSION
  /* Try the .so extension first.  If that fails build a new filename
     using EXTRA_SHLIB_EXTENSION.  */
  if (! ldfile_try_open_bfd (string, entry))
    sprintf (string, "%s/lib%s%s%s", search->name,
	     filename, arch, EXTRA_SHLIB_EXTENSION);
#endif

  if (! ldfile_try_open_bfd (string, entry))
    {
      free (string);
      return FALSE;
    }

  entry->filename = string;

  /* We have found a dynamic object to include in the link.  The ELF
     backend linker will create a DT_NEEDED entry in the .dynamic
     section naming this file.  If this file includes a DT_SONAME
     entry, it will be used.  Otherwise, the ELF linker will just use
     the name of the file.  For an archive found by searching, like
     this one, the DT_NEEDED entry should consist of just the name of
     the file, without the path information used to find it.  Note
     that we only need to do this if we have a dynamic object; an
     archive will never be referenced by a DT_NEEDED entry.

     FIXME: This approach--using bfd_elf_set_dt_needed_name--is not
     very pretty.  I haven't been able to think of anything that is
     pretty, though.  */
  if (bfd_check_format (entry->the_bfd, bfd_object)
      && (entry->the_bfd->flags & DYNAMIC) != 0)
    {
      ASSERT (entry->is_archive && entry->search_dirs_flag);

      /* Rather than duplicating the logic above.  Just use the
	 filename we recorded earlier.  */

      filename = lbasename (entry->filename);
      bfd_elf_set_dt_needed_name (entry->the_bfd, filename);
    }

  return TRUE;
}
Пример #29
0
void
lang_specific_driver (struct cl_decoded_option **in_decoded_options,
		      unsigned int *in_decoded_options_count,
		      int *in_added_libraries)
{
  unsigned int i, j;

  /* If true, the user gave us the `-p' or `-pg' flag.  */
  bool saw_profile_flag = false;

  /* This is a tristate:
     -1 means we should not link in libgo
     0  means we should link in libgo if it is needed
     1  means libgo is needed and should be linked in.
     2  means libgo is needed and should be linked statically.  */
  int library = 0;

  /* The new argument list will be contained in this.  */
  struct cl_decoded_option *new_decoded_options;

  /* "-lm" or "-lmath" if it appears on the command line.  */
  const struct cl_decoded_option *saw_math = 0;

  /* "-lpthread" if it appears on the command line.  */
  const struct cl_decoded_option *saw_thread = 0;

  /* "-lc" if it appears on the command line.  */
  const struct cl_decoded_option *saw_libc = 0;

  /* An array used to flag each argument that needs a bit set for
     LANGSPEC, MATHLIB, or WITHLIBC.  */
  int *args;

  /* Whether we need the thread library.  */
  int need_thread = 0;

  /* By default, we throw on the math library if we have one.  */
  int need_math = (MATH_LIBRARY[0] != '\0');

  /* True if we saw -static.  */
  int static_link = 0;

  /* True if we should add -shared-libgcc to the command-line.  */
  int shared_libgcc = 1;

  /* The total number of arguments with the new stuff.  */
  unsigned int argc;

  /* The argument list.  */
  struct cl_decoded_option *decoded_options;

  /* The number of libraries added in.  */
  int added_libraries;

  /* The total number of arguments with the new stuff.  */
  int num_args = 1;

  /* Whether the -o option was used.  */
  bool saw_opt_o = false;

  /* Whether the -c option was used.  Also used for -E, -fsyntax-only,
     in general anything which implies only compilation and not
     linking.  */
  bool saw_opt_c = false;

  /* Whether the -S option was used.  */
  bool saw_opt_S = false;

  /* The first input file with an extension of .go.  */
  const char *first_go_file = NULL;  

  argc = *in_decoded_options_count;
  decoded_options = *in_decoded_options;
  added_libraries = *in_added_libraries;

  args = XCNEWVEC (int, argc);

  for (i = 1; i < argc; i++)
    {
      const char *arg = decoded_options[i].arg;

      switch (decoded_options[i].opt_index)
	{
	case OPT_nostdlib:
	case OPT_nodefaultlibs:
	  library = -1;
	  break;

	case OPT_l:
	  if (strcmp (arg, MATH_LIBRARY) == 0)
	    {
	      args[i] |= MATHLIB;
	      need_math = 0;
	    }
	  else if (strcmp (arg, THREAD_LIBRARY) == 0)
	    args[i] |= THREADLIB;
	  else if (strcmp (arg, "c") == 0)
	    args[i] |= WITHLIBC;
	  else
	    /* Unrecognized libraries (e.g. -lfoo) may require libgo.  */
	    library = (library == 0) ? 1 : library;
	  break;

	case OPT_pg:
	case OPT_p:
	  saw_profile_flag = true;
	  break;

	case OPT_x:
	  if (library == 0 && strcmp (arg, "go") == 0)
	    library = 1;
	  break;

	case OPT_Xlinker:
	case OPT_Wl_:
	  /* Arguments that go directly to the linker might be .o files,
	     or something, and so might cause libgo to be needed.  */
	  if (library == 0)
	    library = 1;
	  break;

	case OPT_c:
	case OPT_E:
	case OPT_M:
	case OPT_MM:
	case OPT_fsyntax_only:
	  /* Don't specify libraries if we won't link, since that would
	     cause a warning.  */
	  saw_opt_c = true;
	  library = -1;
	  break;

	case OPT_S:
	  saw_opt_S = true;
	  library = -1;
	  break;

	case OPT_o:
	  saw_opt_o = true;
	  break;

	case OPT_static:
	  static_link = 1;
	  break;

	case OPT_static_libgcc:
	  shared_libgcc = 0;
	  break;

	case OPT_static_libgo:
	  library = library >= 0 ? 2 : library;
	  args[i] |= SKIPOPT;
	  break;

	case OPT_SPECIAL_input_file:
	  if (library == 0)
	    library = 1;

	  if (first_go_file == NULL)
	    {
	      int len;

	      len = strlen (arg);
	      if (len > 3 && strcmp (arg + len - 3, ".go") == 0)
		first_go_file = arg;
	    }

	  break;
	}
    }

  /* There's no point adding -shared-libgcc if we don't have a shared
     libgcc.  */
#ifndef ENABLE_SHARED_LIBGCC
  shared_libgcc = 0;
#endif

  /* Make sure to have room for the trailing NULL argument.  */
  num_args = argc + need_math + shared_libgcc + (library > 0) * 5 + 10;
  new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args);

  i = 0;
  j = 0;

  /* Copy the 0th argument, i.e., the name of the program itself.  */
  new_decoded_options[j++] = decoded_options[i++];

  /* If we are linking, pass -fsplit-stack if it is supported.  */
#ifdef TARGET_CAN_SPLIT_STACK
  if (library >= 0)
    {
      generate_option (OPT_fsplit_stack, NULL, 1, CL_DRIVER,
		       &new_decoded_options[j]);
      j++;
    }
#endif

  /* NOTE: We start at 1 now, not 0.  */
  while (i < argc)
    {
      new_decoded_options[j] = decoded_options[i];

      /* Make sure -lgo is before the math library, since libgo itself
	 uses those math routines.  */
      if (!saw_math && (args[i] & MATHLIB) && library > 0)
	{
	  --j;
	  saw_math = &decoded_options[i];
	}

      if (!saw_thread && (args[i] & THREADLIB) && library > 0)
	{
	  --j;
	  saw_thread = &decoded_options[i];
	}

      if (!saw_libc && (args[i] & WITHLIBC) && library > 0)
	{
	  --j;
	  saw_libc = &decoded_options[i];
	}

      if ((args[i] & SKIPOPT) != 0)
	--j;

      i++;
      j++;
    }

  /* If we didn't see a -o option, add one.  This is because we need
     the driver to pass all .go files to go1.  Without a -o option the
     driver will invoke go1 separately for each input file.  FIXME:
     This should probably use some other interface to force the driver
     to set combine_inputs.  */
  if (first_go_file != NULL && !saw_opt_o)
    {
      if (saw_opt_c || saw_opt_S)
	{
	  const char *base;
	  int baselen;
	  int alen;
	  char *out;

	  base = lbasename (first_go_file);
	  baselen = strlen (base) - 3;
	  alen = baselen + 3;
	  out = XNEWVEC (char, alen);
	  memcpy (out, base, baselen);
	  /* The driver will convert .o to some other suffix (e.g.,
	     .obj) if appropriate.  */
	  out[baselen] = '.';
	  if (saw_opt_S)
	    out[baselen + 1] = 's';
	  else
	    out[baselen + 1] = 'o';
	  out[baselen + 2] = '\0';
	  generate_option (OPT_o, out, 1, CL_DRIVER,
			   &new_decoded_options[j]);
	}
      else
	generate_option (OPT_o, "a.out", 1, CL_DRIVER,
			 &new_decoded_options[j]);
      j++;
    }
Пример #30
0
static char *
make_relative_prefix_1 (const char *progname, const char *bin_prefix,
			const char *prefix, const int resolve_links)
{
  char **prog_dirs = NULL, **bin_dirs = NULL, **prefix_dirs = NULL;
  int prog_num, bin_num, prefix_num;
  int i, n, common;
  int needed_len;
  char *ret = NULL, *ptr, *full_progname;

  if (progname == NULL || bin_prefix == NULL || prefix == NULL)
        return NULL;

  /* If there is no full pathname, try to find the program by checking in each
     of the directories specified in the PATH environment variable.  */
    if (lbasename (progname) == progname)
    {
        char *temp;

#if 0
        temp = getenv ("PATH");

        if (temp)
        {
            char *startp, *endp, *nstore;
            size_t prefixlen = strlen (temp) + 1;
            size_t len;
            if (prefixlen < 2)
                prefixlen = 2;

            len = prefixlen + strlen (progname) + 1;
#ifdef HAVE_HOST_EXECUTABLE_SUFFIX
            len += strlen (HOST_EXECUTABLE_SUFFIX);
#endif
            nstore = (char *) alloca (len);

            startp = endp = temp;
            while (1)
            {
                if (*endp == PATH_SEPARATOR || *endp == 0)
                {
                    if (endp == startp)
                    {
                        nstore[0] = '.';
                        nstore[1] = DIR_SEPARATOR;
                        nstore[2] = '\0';
                    }
                    else
                    {
                        memcpy (nstore, startp, endp - startp);
                        if (! IS_DIR_SEPARATOR (endp[-1]))
                        {
                            nstore[endp - startp] = DIR_SEPARATOR;
                            nstore[endp - startp + 1] = 0;
                        }
                        else
                            nstore[endp - startp] = 0;
                     }
                    strcat (nstore, progname);
                    if (! access (nstore, X_OK)
#ifdef HAVE_HOST_EXECUTABLE_SUFFIX
                        || ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK)
#endif
                        )
                    {
#if defined (HAVE_SYS_STAT_H) && defined (S_ISREG)
                        struct stat st;
                        if (stat (nstore, &st) >= 0 && S_ISREG (st.st_mode))
#endif
                        {
                            progname = nstore;
                            break;
                        }
                    }

                    if (*endp == 0)
                        break;
                    endp = startp = endp + 1;
                }
                else
                    endp++;
            }
        }
#endif

  }

  if (resolve_links)
    full_progname = lrealpath (progname);
  else
    full_progname = strdup (progname);
  if (full_progname == NULL)
    return NULL;

  prog_dirs = split_directories (full_progname, &prog_num);
  free (full_progname);
  if (prog_dirs == NULL)
    return NULL;

  bin_dirs = split_directories (bin_prefix, &bin_num);
  if (bin_dirs == NULL)
    goto bailout;

  /* Remove the program name from comparison of directory names.  */
  prog_num--;

  /* If we are still installed in the standard location, we don't need to
     specify relative directories.  Also, if argv[0] still doesn't contain
     any directory specifiers after the search above, then there is not much
     we can do.  */
  if (prog_num == bin_num)
    {
      for (i = 0; i < bin_num; i++)
	{
	  if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
	    break;
	}

      if (prog_num <= 0 || i == bin_num)
	goto bailout;
    }

  prefix_dirs = split_directories (prefix, &prefix_num);
  if (prefix_dirs == NULL)
    goto bailout;

  /* Find how many directories are in common between bin_prefix & prefix.  */
  n = (prefix_num < bin_num) ? prefix_num : bin_num;
  for (common = 0; common < n; common++)
    {
      if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
	break;
    }

  /* If there are no common directories, there can be no relative prefix.  */
  if (common == 0)
    goto bailout;

  /* Two passes: first figure out the size of the result string, and
     then construct it.  */
  needed_len = 0;
  for (i = 0; i < prog_num; i++)
    needed_len += strlen (prog_dirs[i]);
  needed_len += sizeof (DIR_UP) * (bin_num - common);
  for (i = common; i < prefix_num; i++)
    needed_len += strlen (prefix_dirs[i]);
  needed_len += 1; /* Trailing NUL.  */

  ret = (char *) malloc (needed_len);
  if (ret == NULL)
    goto bailout;

  /* Build up the pathnames in argv[0].  */
  *ret = '\0';
  for (i = 0; i < prog_num; i++)
    strcat (ret, prog_dirs[i]);

  /* Now build up the ..'s.  */
  ptr = ret + strlen(ret);
  for (i = common; i < bin_num; i++)
    {
      strcpy (ptr, DIR_UP);
      ptr += sizeof (DIR_UP) - 1;
      *(ptr++) = DIR_SEPARATOR;
    }
  *ptr = '\0';

  /* Put in directories to move over to prefix.  */
  for (i = common; i < prefix_num; i++)
    strcat (ret, prefix_dirs[i]);

 bailout:
  free_split_directories (prog_dirs);
  free_split_directories (bin_dirs);
  free_split_directories (prefix_dirs);

  return ret;
}