Blame elf/dl-misc.c

Packit 6c4009
/* Miscellaneous support functions for dynamic linker
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <link.h>
Packit 6c4009
#include <stdarg.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include <_itoa.h>
Packit 6c4009
#include <dl-writev.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
Packit 6c4009
/* Read the whole contents of FILE into new mmap'd space with given
Packit 6c4009
   protections.  *SIZEP gets the size of the file.  On error MAP_FAILED
Packit 6c4009
   is returned.  */
Packit 6c4009
Packit 6c4009
void *
Packit 6c4009
_dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
Packit 6c4009
{
Packit 6c4009
  void *result = MAP_FAILED;
Packit 6c4009
  struct stat64 st;
Packit 6c4009
  int fd = __open64_nocancel (file, O_RDONLY | O_CLOEXEC);
Packit 6c4009
  if (fd >= 0)
Packit 6c4009
    {
Packit 6c4009
      if (__fxstat64 (_STAT_VER, fd, &st) >= 0)
Packit 6c4009
	{
Packit 6c4009
	  *sizep = st.st_size;
Packit 6c4009
Packit 6c4009
	  /* No need to map the file if it is empty.  */
Packit 6c4009
	  if (*sizep != 0)
Packit 6c4009
	    /* Map a copy of the file contents.  */
Packit 6c4009
	    result = __mmap (NULL, *sizep, prot,
Packit 6c4009
#ifdef MAP_COPY
Packit 6c4009
			     MAP_COPY
Packit 6c4009
#else
Packit 6c4009
			     MAP_PRIVATE
Packit 6c4009
#endif
Packit 6c4009
#ifdef MAP_FILE
Packit 6c4009
			     | MAP_FILE
Packit 6c4009
#endif
Packit 6c4009
			     , fd, 0);
Packit 6c4009
	}
Packit 6c4009
      __close_nocancel (fd);
Packit 6c4009
    }
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Bare-bones printf implementation.  This function only knows about
Packit 6c4009
   the formats and flags needed and can handle only up to 64 stripes in
Packit 6c4009
   the output.  */
Packit 6c4009
static void
Packit 6c4009
_dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
Packit 6c4009
{
Packit 6c4009
# define NIOVMAX 64
Packit 6c4009
  struct iovec iov[NIOVMAX];
Packit 6c4009
  int niov = 0;
Packit 6c4009
  pid_t pid = 0;
Packit 6c4009
  char pidbuf[12];
Packit 6c4009
Packit 6c4009
  while (*fmt != '\0')
Packit 6c4009
    {
Packit 6c4009
      const char *startp = fmt;
Packit 6c4009
Packit 6c4009
      if (tag_p > 0)
Packit 6c4009
	{
Packit 6c4009
	  /* Generate the tag line once.  It consists of the PID and a
Packit 6c4009
	     colon followed by a tab.  */
Packit 6c4009
	  if (pid == 0)
Packit 6c4009
	    {
Packit 6c4009
	      char *p;
Packit 6c4009
	      pid = __getpid ();
Packit 6c4009
	      assert (pid >= 0 && sizeof (pid_t) <= 4);
Packit 6c4009
	      p = _itoa (pid, &pidbuf[10], 10, 0);
Packit 6c4009
	      while (p > pidbuf)
Packit 6c4009
		*--p = ' ';
Packit 6c4009
	      pidbuf[10] = ':';
Packit 6c4009
	      pidbuf[11] = '\t';
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Append to the output.  */
Packit 6c4009
	  assert (niov < NIOVMAX);
Packit 6c4009
	  iov[niov].iov_len = 12;
Packit 6c4009
	  iov[niov++].iov_base = pidbuf;
Packit 6c4009
Packit 6c4009
	  /* No more tags until we see the next newline.  */
Packit 6c4009
	  tag_p = -1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Skip everything except % and \n (if tags are needed).  */
Packit 6c4009
      while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n'))
Packit 6c4009
	++fmt;
Packit 6c4009
Packit 6c4009
      /* Append constant string.  */
Packit 6c4009
      assert (niov < NIOVMAX);
Packit 6c4009
      if ((iov[niov].iov_len = fmt - startp) != 0)
Packit 6c4009
	iov[niov++].iov_base = (char *) startp;
Packit 6c4009
Packit 6c4009
      if (*fmt == '%')
Packit 6c4009
	{
Packit 6c4009
	  /* It is a format specifier.  */
Packit 6c4009
	  char fill = ' ';
Packit 6c4009
	  int width = -1;
Packit 6c4009
	  int prec = -1;
Packit 6c4009
#if LONG_MAX != INT_MAX
Packit 6c4009
	  int long_mod = 0;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  /* Recognize zero-digit fill flag.  */
Packit 6c4009
	  if (*++fmt == '0')
Packit 6c4009
	    {
Packit 6c4009
	      fill = '0';
Packit 6c4009
	      ++fmt;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* See whether with comes from a parameter.  Note that no other
Packit 6c4009
	     way to specify the width is implemented.  */
Packit 6c4009
	  if (*fmt == '*')
Packit 6c4009
	    {
Packit 6c4009
	      width = va_arg (arg, int);
Packit 6c4009
	      ++fmt;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Handle precision.  */
Packit 6c4009
	  if (*fmt == '.' && fmt[1] == '*')
Packit 6c4009
	    {
Packit 6c4009
	      prec = va_arg (arg, int);
Packit 6c4009
	      fmt += 2;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Recognize the l modifier.  It is only important on some
Packit 6c4009
	     platforms where long and int have a different size.  We
Packit 6c4009
	     can use the same code for size_t.  */
Packit 6c4009
	  if (*fmt == 'l' || *fmt == 'Z')
Packit 6c4009
	    {
Packit 6c4009
#if LONG_MAX != INT_MAX
Packit 6c4009
	      long_mod = 1;
Packit 6c4009
#endif
Packit 6c4009
	      ++fmt;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  switch (*fmt)
Packit 6c4009
	    {
Packit 6c4009
	      /* Integer formatting.  */
Packit Service 447893
	    case 'd':
Packit 6c4009
	    case 'u':
Packit 6c4009
	    case 'x':
Packit 6c4009
	      {
Packit 6c4009
		/* We have to make a difference if long and int have a
Packit 6c4009
		   different size.  */
Packit 6c4009
#if LONG_MAX != INT_MAX
Packit 6c4009
		unsigned long int num = (long_mod
Packit 6c4009
					 ? va_arg (arg, unsigned long int)
Packit 6c4009
					 : va_arg (arg, unsigned int));
Packit 6c4009
#else
Packit 6c4009
		unsigned long int num = va_arg (arg, unsigned int);
Packit 6c4009
#endif
Packit Service 447893
		bool negative = false;
Packit Service 447893
		if (*fmt == 'd')
Packit Service 447893
		  {
Packit Service 447893
#if LONG_MAX != INT_MAX
Packit Service 447893
		    if (long_mod)
Packit Service 447893
		      {
Packit Service 447893
			if ((long int) num < 0)
Packit Service 447893
			  negative = true;
Packit Service 447893
		      }
Packit Service 447893
		    else
Packit Service 447893
		      {
Packit Service 447893
			if ((int) num < 0)
Packit Service 447893
			  {
Packit Service 447893
			    num = (unsigned int) num;
Packit Service 447893
			    negative = true;
Packit Service 447893
			  }
Packit Service 447893
		      }
Packit Service 447893
#else
Packit Service 447893
		    if ((int) num < 0)
Packit Service 447893
		      negative = true;
Packit Service 447893
#endif
Packit Service 447893
		  }
Packit Service 447893
Packit 6c4009
		/* We use alloca() to allocate the buffer with the most
Packit 6c4009
		   pessimistic guess for the size.  Using alloca() allows
Packit 6c4009
		   having more than one integer formatting in a call.  */
Packit Service 447893
		char *buf = (char *) alloca (1 + 3 * sizeof (unsigned long int));
Packit Service 447893
		char *endp = &buf[1 + 3 * sizeof (unsigned long int)];
Packit 6c4009
		char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
Packit 6c4009
Packit 6c4009
		/* Pad to the width the user specified.  */
Packit 6c4009
		if (width != -1)
Packit 6c4009
		  while (endp - cp < width)
Packit 6c4009
		    *--cp = fill;
Packit 6c4009
Packit Service 447893
		if (negative)
Packit Service 447893
		  *--cp = '-';
Packit Service 447893
Packit 6c4009
		iov[niov].iov_base = cp;
Packit 6c4009
		iov[niov].iov_len = endp - cp;
Packit 6c4009
		++niov;
Packit 6c4009
	      }
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    case 's':
Packit 6c4009
	      /* Get the string argument.  */
Packit 6c4009
	      iov[niov].iov_base = va_arg (arg, char *);
Packit 6c4009
	      iov[niov].iov_len = strlen (iov[niov].iov_base);
Packit 6c4009
	      if (prec != -1)
Packit 6c4009
		iov[niov].iov_len = MIN ((size_t) prec, iov[niov].iov_len);
Packit 6c4009
	      ++niov;
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    case '%':
Packit 6c4009
	      iov[niov].iov_base = (void *) fmt;
Packit 6c4009
	      iov[niov].iov_len = 1;
Packit 6c4009
	      ++niov;
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    default:
Packit 6c4009
	      assert (! "invalid format specifier");
Packit 6c4009
	    }
Packit 6c4009
	  ++fmt;
Packit 6c4009
	}
Packit 6c4009
      else if (*fmt == '\n')
Packit 6c4009
	{
Packit 6c4009
	  /* See whether we have to print a single newline character.  */
Packit 6c4009
	  if (fmt == startp)
Packit 6c4009
	    {
Packit 6c4009
	      iov[niov].iov_base = (char *) startp;
Packit 6c4009
	      iov[niov++].iov_len = 1;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    /* No, just add it to the rest of the string.  */
Packit 6c4009
	    ++iov[niov - 1].iov_len;
Packit 6c4009
Packit 6c4009
	  /* Next line, print a tag again.  */
Packit 6c4009
	  tag_p = 1;
Packit 6c4009
	  ++fmt;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Finally write the result.  */
Packit 6c4009
  _dl_writev (fd, iov, niov);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Write to debug file.  */
Packit 6c4009
void
Packit 6c4009
_dl_debug_printf (const char *fmt, ...)
Packit 6c4009
{
Packit 6c4009
  va_list arg;
Packit 6c4009
Packit 6c4009
  va_start (arg, fmt);
Packit 6c4009
  _dl_debug_vdprintf (GLRO(dl_debug_fd), 1, fmt, arg);
Packit 6c4009
  va_end (arg);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Write to debug file but don't start with a tag.  */
Packit 6c4009
void
Packit 6c4009
_dl_debug_printf_c (const char *fmt, ...)
Packit 6c4009
{
Packit 6c4009
  va_list arg;
Packit 6c4009
Packit 6c4009
  va_start (arg, fmt);
Packit 6c4009
  _dl_debug_vdprintf (GLRO(dl_debug_fd), -1, fmt, arg);
Packit 6c4009
  va_end (arg);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Write the given file descriptor.  */
Packit 6c4009
void
Packit 6c4009
_dl_dprintf (int fd, const char *fmt, ...)
Packit 6c4009
{
Packit 6c4009
  va_list arg;
Packit 6c4009
Packit 6c4009
  va_start (arg, fmt);
Packit 6c4009
  _dl_debug_vdprintf (fd, 0, fmt, arg);
Packit 6c4009
  va_end (arg);
Packit 6c4009
}
Packit 6c4009
Packit Service 1e78da
void
Packit Service 1e78da
_dl_printf (const char *fmt, ...)
Packit Service 1e78da
{
Packit Service 1e78da
  va_list arg;
Packit Service 1e78da
Packit Service 1e78da
  va_start (arg, fmt);
Packit Service 1e78da
  _dl_debug_vdprintf (STDOUT_FILENO, 0, fmt, arg);
Packit Service 1e78da
  va_end (arg);
Packit Service 1e78da
}
Packit Service 1e78da
Packit Service 1e78da
void
Packit Service 1e78da
_dl_error_printf (const char *fmt, ...)
Packit Service 1e78da
{
Packit Service 1e78da
  va_list arg;
Packit Service 1e78da
Packit Service 1e78da
  va_start (arg, fmt);
Packit Service 1e78da
  _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
Packit Service 1e78da
  va_end (arg);
Packit Service 1e78da
}
Packit Service 1e78da
Packit Service 1e78da
void
Packit Service 1e78da
_dl_fatal_printf (const char *fmt, ...)
Packit Service 1e78da
{
Packit Service 1e78da
  va_list arg;
Packit Service 1e78da
Packit Service 1e78da
  va_start (arg, fmt);
Packit Service 1e78da
  _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
Packit Service 1e78da
  va_end (arg);
Packit Service 1e78da
  _exit (127);
Packit Service 1e78da
}
Packit Service 1e78da
rtld_hidden_def (_dl_fatal_printf)
Packit 6c4009
Packit 6c4009
/* Test whether given NAME matches any of the names of the given object.  */
Packit 6c4009
int
Packit 6c4009
_dl_name_match_p (const char *name, const struct link_map *map)
Packit 6c4009
{
Packit 6c4009
  if (strcmp (name, map->l_name) == 0)
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  struct libname_list *runp = map->l_libname;
Packit 6c4009
Packit 6c4009
  while (runp != NULL)
Packit 6c4009
    if (strcmp (name, runp->name) == 0)
Packit 6c4009
      return 1;
Packit 6c4009
    else
Packit 6c4009
      runp = runp->next;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
unsigned long int
Packit 6c4009
_dl_higher_prime_number (unsigned long int n)
Packit 6c4009
{
Packit 6c4009
  /* These are primes that are near, but slightly smaller than, a
Packit 6c4009
     power of two.  */
Packit 6c4009
  static const uint32_t primes[] = {
Packit 6c4009
    UINT32_C (7),
Packit 6c4009
    UINT32_C (13),
Packit 6c4009
    UINT32_C (31),
Packit 6c4009
    UINT32_C (61),
Packit 6c4009
    UINT32_C (127),
Packit 6c4009
    UINT32_C (251),
Packit 6c4009
    UINT32_C (509),
Packit 6c4009
    UINT32_C (1021),
Packit 6c4009
    UINT32_C (2039),
Packit 6c4009
    UINT32_C (4093),
Packit 6c4009
    UINT32_C (8191),
Packit 6c4009
    UINT32_C (16381),
Packit 6c4009
    UINT32_C (32749),
Packit 6c4009
    UINT32_C (65521),
Packit 6c4009
    UINT32_C (131071),
Packit 6c4009
    UINT32_C (262139),
Packit 6c4009
    UINT32_C (524287),
Packit 6c4009
    UINT32_C (1048573),
Packit 6c4009
    UINT32_C (2097143),
Packit 6c4009
    UINT32_C (4194301),
Packit 6c4009
    UINT32_C (8388593),
Packit 6c4009
    UINT32_C (16777213),
Packit 6c4009
    UINT32_C (33554393),
Packit 6c4009
    UINT32_C (67108859),
Packit 6c4009
    UINT32_C (134217689),
Packit 6c4009
    UINT32_C (268435399),
Packit 6c4009
    UINT32_C (536870909),
Packit 6c4009
    UINT32_C (1073741789),
Packit 6c4009
    UINT32_C (2147483647),
Packit 6c4009
				       /* 4294967291L */
Packit 6c4009
    UINT32_C (2147483647) + UINT32_C (2147483644)
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
  const uint32_t *low = &primes[0];
Packit 6c4009
  const uint32_t *high = &primes[sizeof (primes) / sizeof (primes[0])];
Packit 6c4009
Packit 6c4009
  while (low != high)
Packit 6c4009
    {
Packit 6c4009
      const uint32_t *mid = low + (high - low) / 2;
Packit 6c4009
      if (n > *mid)
Packit 6c4009
       low = mid + 1;
Packit 6c4009
      else
Packit 6c4009
       high = mid;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#if 0
Packit 6c4009
  /* If we've run out of primes, abort.  */
Packit 6c4009
  if (n > *low)
Packit 6c4009
    {
Packit 6c4009
      fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
Packit 6c4009
      abort ();
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  return *low;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* A stripped down strtoul-like implementation for very early use.  It
Packit 6c4009
   does not set errno if the result is outside bounds because it may get
Packit 6c4009
   called before errno may have been set up.  */
Packit 6c4009
Packit 6c4009
uint64_t
Packit 6c4009
_dl_strtoul (const char *nptr, char **endptr)
Packit 6c4009
{
Packit 6c4009
  uint64_t result = 0;
Packit 6c4009
  bool positive = true;
Packit 6c4009
  unsigned max_digit;
Packit 6c4009
Packit 6c4009
  while (*nptr == ' ' || *nptr == '\t')
Packit 6c4009
    ++nptr;
Packit 6c4009
Packit 6c4009
  if (*nptr == '-')
Packit 6c4009
    {
Packit 6c4009
      positive = false;
Packit 6c4009
      ++nptr;
Packit 6c4009
    }
Packit 6c4009
  else if (*nptr == '+')
Packit 6c4009
    ++nptr;
Packit 6c4009
Packit 6c4009
  if (*nptr < '0' || *nptr > '9')
Packit 6c4009
    {
Packit 6c4009
      if (endptr != NULL)
Packit 6c4009
	*endptr = (char *) nptr;
Packit 6c4009
      return 0UL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  int base = 10;
Packit 6c4009
  max_digit = 9;
Packit 6c4009
  if (*nptr == '0')
Packit 6c4009
    {
Packit 6c4009
      if (nptr[1] == 'x' || nptr[1] == 'X')
Packit 6c4009
	{
Packit 6c4009
	  base = 16;
Packit 6c4009
	  nptr += 2;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  base = 8;
Packit 6c4009
	  max_digit = 7;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      int digval;
Packit 6c4009
      if (*nptr >= '0' && *nptr <= '0' + max_digit)
Packit 6c4009
        digval = *nptr - '0';
Packit 6c4009
      else if (base == 16)
Packit 6c4009
        {
Packit 6c4009
	  if (*nptr >= 'a' && *nptr <= 'f')
Packit 6c4009
	    digval = *nptr - 'a' + 10;
Packit 6c4009
	  else if (*nptr >= 'A' && *nptr <= 'F')
Packit 6c4009
	    digval = *nptr - 'A' + 10;
Packit 6c4009
	  else
Packit 6c4009
	    break;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
        break;
Packit 6c4009
Packit 6c4009
      if (result >= (UINT64_MAX - digval) / base)
Packit 6c4009
	{
Packit 6c4009
	  if (endptr != NULL)
Packit 6c4009
	    *endptr = (char *) nptr;
Packit 6c4009
	  return UINT64_MAX;
Packit 6c4009
	}
Packit 6c4009
      result *= base;
Packit 6c4009
      result += digval;
Packit 6c4009
      ++nptr;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (endptr != NULL)
Packit 6c4009
    *endptr = (char *) nptr;
Packit 6c4009
Packit 6c4009
  /* Avoid 64-bit multiplication.  */
Packit 6c4009
  if (!positive)
Packit 6c4009
    result = -result;
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}