Blame elf/dl-misc.c

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