(root)/
glibc-2.38/
elf/
dl-printf.c
       1  /* printf implementation for the dynamic loader.
       2     Copyright (C) 1997-2023 Free Software Foundation, Inc.
       3     Copyright The GNU Toolchain Authors.
       4     This file is part of the GNU C Library.
       5  
       6     The GNU C Library is free software; you can redistribute it and/or
       7     modify it under the terms of the GNU Lesser General Public
       8     License as published by the Free Software Foundation; either
       9     version 2.1 of the License, or (at your option) any later version.
      10  
      11     The GNU C Library is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14     Lesser General Public License for more details.
      15  
      16     You should have received a copy of the GNU Lesser General Public
      17     License along with the GNU C Library; if not, see
      18     <https://www.gnu.org/licenses/>.  */
      19  
      20  #include <_itoa.h>
      21  #include <assert.h>
      22  #include <dl-writev.h>
      23  #include <ldsodefs.h>
      24  #include <limits.h>
      25  #include <stdarg.h>
      26  #include <stdint.h>
      27  #include <stdlib.h>
      28  #include <string.h>
      29  #include <sys/uio.h>
      30  #include <unistd.h>
      31  #include <intprops.h>
      32  
      33  /* Bare-bones printf implementation.  This function only knows about
      34     the formats and flags needed and can handle only up to 64 stripes in
      35     the output.  */
      36  static void
      37  _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
      38  {
      39  # define NIOVMAX 64
      40    struct iovec iov[NIOVMAX];
      41    /* Maximum size for 'd', 'u', and 'x' including padding.  */
      42    enum { IFMTSIZE = INT_STRLEN_BOUND(void *) };
      43    char ifmtbuf[NIOVMAX][IFMTSIZE];
      44    int niov = 0;
      45    pid_t pid = 0;
      46    char pidbuf[12];
      47  
      48    while (*fmt != '\0')
      49      {
      50        const char *startp = fmt;
      51  
      52        if (tag_p > 0)
      53  	{
      54  	  /* Generate the tag line once.  It consists of the PID and a
      55  	     colon followed by a tab.  */
      56  	  if (pid == 0)
      57  	    {
      58  	      char *p;
      59  	      pid = __getpid ();
      60  	      assert (pid >= 0 && sizeof (pid_t) <= 4);
      61  	      p = _itoa (pid, &pidbuf[10], 10, 0);
      62  	      while (p > pidbuf)
      63  		*--p = ' ';
      64  	      pidbuf[10] = ':';
      65  	      pidbuf[11] = '\t';
      66  	    }
      67  
      68  	  /* Append to the output.  */
      69  	  assert (niov < NIOVMAX);
      70  	  iov[niov].iov_len = 12;
      71  	  iov[niov++].iov_base = pidbuf;
      72  
      73  	  /* No more tags until we see the next newline.  */
      74  	  tag_p = -1;
      75  	}
      76  
      77        /* Skip everything except % and \n (if tags are needed).  */
      78        while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n'))
      79  	++fmt;
      80  
      81        /* Append constant string.  */
      82        assert (niov < NIOVMAX);
      83        if ((iov[niov].iov_len = fmt - startp) != 0)
      84  	iov[niov++].iov_base = (char *) startp;
      85  
      86        if (*fmt == '%')
      87  	{
      88  	  /* It is a format specifier.  */
      89  	  char fill = ' ';
      90  	  int width = -1;
      91  	  int prec = -1;
      92  #if LONG_MAX != INT_MAX
      93  	  int long_mod = 0;
      94  #endif
      95  
      96  	  /* Recognize zero-digit fill flag.  */
      97  	  if (*++fmt == '0')
      98  	    {
      99  	      fill = '0';
     100  	      ++fmt;
     101  	    }
     102  
     103  	  /* See whether with comes from a parameter.  Note that no other
     104  	     way to specify the width is implemented.  */
     105  	  if (*fmt == '*')
     106  	    {
     107  	      width = va_arg (arg, int);
     108  	      /* The maximum padding accepted is up to pointer size.  */
     109  	      assert (width < IFMTSIZE);
     110  	      ++fmt;
     111  	    }
     112  
     113  	  /* Handle precision.  */
     114  	  if (*fmt == '.' && fmt[1] == '*')
     115  	    {
     116  	      prec = va_arg (arg, int);
     117  	      fmt += 2;
     118  	    }
     119  
     120  	  /* Recognize the l modifier.  It is only important on some
     121  	     platforms where long and int have a different size.  We
     122  	     can use the same code for size_t.  */
     123  	  if (*fmt == 'l' || *fmt == 'z')
     124  	    {
     125  #if LONG_MAX != INT_MAX
     126  	      long_mod = 1;
     127  #endif
     128  	      ++fmt;
     129  	    }
     130  
     131  	  switch (*fmt)
     132  	    {
     133  	      /* Integer formatting.  */
     134  	    case 'd':
     135  	    case 'u':
     136  	    case 'x':
     137  	      {
     138  		/* We have to make a difference if long and int have a
     139  		   different size.  */
     140  #if LONG_MAX != INT_MAX
     141  		unsigned long int num = (long_mod
     142  					 ? va_arg (arg, unsigned long int)
     143  					 : va_arg (arg, unsigned int));
     144  #else
     145  		unsigned long int num = va_arg (arg, unsigned int);
     146  #endif
     147  		bool negative = false;
     148  		if (*fmt == 'd')
     149  		  {
     150  #if LONG_MAX != INT_MAX
     151  		    if (long_mod)
     152  		      {
     153  			if ((long int) num < 0)
     154  			  {
     155  			    num = -num;
     156  			    negative = true;
     157  			  }
     158  		      }
     159  		    else
     160  		      {
     161  			if ((int) num < 0)
     162  			  {
     163  			    num = -(unsigned int) num;
     164  			    negative = true;
     165  			  }
     166  		      }
     167  #else
     168  		    if ((int) num < 0)
     169  		      {
     170  			num = -num;
     171  			negative = true;
     172  		      }
     173  #endif
     174  		  }
     175  
     176  		char *endp = &ifmtbuf[niov][IFMTSIZE];
     177  		char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
     178  
     179  		/* Pad to the width the user specified.  */
     180  		if (width != -1)
     181  		  while (endp - cp < width)
     182  		    *--cp = fill;
     183  
     184  		if (negative)
     185  		  *--cp = '-';
     186  
     187  		iov[niov].iov_base = cp;
     188  		iov[niov].iov_len = endp - cp;
     189  		++niov;
     190  	      }
     191  	      break;
     192  
     193  	    case 's':
     194  	      /* Get the string argument.  */
     195  	      iov[niov].iov_base = va_arg (arg, char *);
     196  	      iov[niov].iov_len = strlen (iov[niov].iov_base);
     197  	      if (prec != -1)
     198  		iov[niov].iov_len = MIN ((size_t) prec, iov[niov].iov_len);
     199  	      ++niov;
     200  	      break;
     201  
     202  	    case '%':
     203  	      iov[niov].iov_base = (void *) fmt;
     204  	      iov[niov].iov_len = 1;
     205  	      ++niov;
     206  	      break;
     207  
     208  	    default:
     209  	      assert (! "invalid format specifier");
     210  	    }
     211  	  ++fmt;
     212  	}
     213        else if (*fmt == '\n')
     214  	{
     215  	  /* See whether we have to print a single newline character.  */
     216  	  if (fmt == startp)
     217  	    {
     218  	      iov[niov].iov_base = (char *) startp;
     219  	      iov[niov++].iov_len = 1;
     220  	    }
     221  	  else
     222  	    /* No, just add it to the rest of the string.  */
     223  	    ++iov[niov - 1].iov_len;
     224  
     225  	  /* Next line, print a tag again.  */
     226  	  tag_p = 1;
     227  	  ++fmt;
     228  	}
     229      }
     230  
     231    /* Finally write the result.  */
     232    _dl_writev (fd, iov, niov);
     233  }
     234  
     235  
     236  /* Write to debug file.  */
     237  void
     238  _dl_debug_printf (const char *fmt, ...)
     239  {
     240    va_list arg;
     241  
     242    va_start (arg, fmt);
     243    _dl_debug_vdprintf (GLRO(dl_debug_fd), 1, fmt, arg);
     244    va_end (arg);
     245  }
     246  
     247  
     248  /* Write to debug file but don't start with a tag.  */
     249  void
     250  _dl_debug_printf_c (const char *fmt, ...)
     251  {
     252    va_list arg;
     253  
     254    va_start (arg, fmt);
     255    _dl_debug_vdprintf (GLRO(dl_debug_fd), -1, fmt, arg);
     256    va_end (arg);
     257  }
     258  
     259  
     260  /* Write the given file descriptor.  */
     261  void
     262  _dl_dprintf (int fd, const char *fmt, ...)
     263  {
     264    va_list arg;
     265  
     266    va_start (arg, fmt);
     267    _dl_debug_vdprintf (fd, 0, fmt, arg);
     268    va_end (arg);
     269  }
     270  
     271  void
     272  _dl_printf (const char *fmt, ...)
     273  {
     274    va_list arg;
     275  
     276    va_start (arg, fmt);
     277    _dl_debug_vdprintf (STDOUT_FILENO, 0, fmt, arg);
     278    va_end (arg);
     279  }
     280  
     281  void
     282  _dl_error_printf (const char *fmt, ...)
     283  {
     284    va_list arg;
     285  
     286    va_start (arg, fmt);
     287    _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
     288    va_end (arg);
     289  }
     290  
     291  void
     292  _dl_fatal_printf (const char *fmt, ...)
     293  {
     294    va_list arg;
     295  
     296    va_start (arg, fmt);
     297    _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
     298    va_end (arg);
     299    _exit (127);
     300  }
     301  rtld_hidden_def (_dl_fatal_printf)