1  /* Trace calls through PLTs and show caller, callee, and parameters.
       2     Copyright (C) 2011-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <err.h>
      20  #include <error.h>
      21  #include <fcntl.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  #include <unistd.h>
      26  #include <sys/param.h>
      27  #include <sys/uio.h>
      28  
      29  #include <ldsodefs.h>
      30  
      31  
      32  extern const char *__progname;
      33  extern const char *__progname_full;
      34  
      35  
      36  /* List of objects to trace calls from.  */
      37  static const char *fromlist;
      38  /* List of objects to trace calls to.  */
      39  static const char *tolist;
      40  
      41  /* If non-zero, also trace returns of the calls.  */
      42  static int do_exit;
      43  /* If non-zero print PID for each line.  */
      44  static int print_pid;
      45  
      46  /* The output stream to use.  */
      47  static FILE *out_file;
      48  
      49  
      50  static int
      51  match_pid (pid_t pid, const char *which)
      52  {
      53    if (which == NULL || which[0] == '\0')
      54      {
      55        print_pid = 1;
      56        return 1;
      57      }
      58  
      59    char *endp;
      60    unsigned long n = strtoul (which, &endp, 0);
      61    return *endp == '\0' && n == pid;
      62  }
      63  
      64  
      65  static void
      66  init (void)
      67  {
      68    fromlist = getenv ("SOTRUSS_FROMLIST");
      69    if (fromlist != NULL && fromlist[0] == '\0')
      70      fromlist = NULL;
      71    tolist = getenv ("SOTRUSS_TOLIST");
      72    if (tolist != NULL && tolist[0] == '\0')
      73      tolist = NULL;
      74    do_exit = (getenv ("SOTRUSS_EXIT") ?: "")[0] != '\0';
      75  
      76    /* Determine whether this process is supposed to be traced and if
      77       yes, whether we should print into a file.  */
      78    const char *which_process = getenv ("SOTRUSS_WHICH");
      79    pid_t pid = getpid ();
      80    int out_fd = -1;
      81    if (match_pid (pid, which_process))
      82      {
      83        const char *out_filename = getenv ("SOTRUSS_OUTNAME");
      84  
      85        if (out_filename != NULL && out_filename[0] != 0)
      86  	{
      87  	  size_t out_filename_len = strlen (out_filename) + 13;
      88  	  char fullname[out_filename_len];
      89  	  char *endp = stpcpy (fullname, out_filename);
      90  	  if (which_process == NULL || which_process[0] == '\0')
      91  	    snprintf (endp, 13, ".%ld", (long int) pid);
      92  
      93  	  out_fd = open64 (fullname, O_RDWR | O_CREAT | O_TRUNC, 0666);
      94  	  if (out_fd != -1)
      95  	    print_pid = 0;
      96  	}
      97      }
      98  
      99    /* If we do not write into a file write to stderr.  Duplicate the
     100       descriptor so that we can keep printing in case the program
     101       closes stderr.  Try first to allocate a descriptor with a value
     102       usually not used as to minimize interference with the
     103       program.  */
     104    if (out_fd == -1)
     105      {
     106        out_fd = fcntl64 (STDERR_FILENO, F_DUPFD, 1000);
     107        if (out_fd == -1)
     108  	out_fd = dup (STDERR_FILENO);
     109      }
     110  
     111    if (out_fd != -1)
     112      {
     113        /* Convert file descriptor into a stream.  */
     114        out_file = fdopen (out_fd, "w");
     115        if (out_file != NULL)
     116  	setlinebuf (out_file);
     117      }
     118  }
     119  
     120  
     121  /* Audit interface verification.  We also initialize everything if
     122     everything checks out OK.  */
     123  unsigned int
     124  la_version (unsigned int v)
     125  {
     126    if (v != LAV_CURRENT)
     127      error (1, 0, "cannot handle interface version %u", v);
     128  
     129    init ();
     130  
     131    return v;
     132  }
     133  
     134  
     135  /* Check whether a file name is on the colon-separated list of file
     136     names.  */
     137  static unsigned int
     138  match_file (const char *list, const char *name, size_t name_len,
     139  	    unsigned int mask)
     140  {
     141    if (list[0] == '\0')
     142      return 0;
     143  
     144    const char *cp = list;
     145    while (1)
     146      {
     147        if (strncmp (cp, name, name_len) == 0
     148  	  && (cp[name_len] == ':' || cp[name_len] == '\0'))
     149  	return mask;
     150  
     151        cp = strchr (cp, ':');
     152        if (cp == NULL)
     153  	return 0;
     154        ++cp;
     155      }
     156  }
     157  
     158  
     159  unsigned int
     160  la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
     161  {
     162    if (out_file == NULL)
     163      return 0;
     164  
     165    const char *full_name = map->l_name ?: "";
     166    if (full_name[0] == '\0')
     167      full_name = __progname_full;
     168    size_t full_name_len = strlen (full_name);
     169    const char *base_name = basename (full_name);
     170    if (base_name[0] == '\0')
     171      base_name = __progname;
     172    size_t base_name_len = strlen (base_name);
     173  
     174    int result = 0;
     175    const char *print_name = NULL;
     176    for (struct libname_list *l = map->l_libname; l != NULL; l = l->next)
     177      {
     178        if (print_name == NULL || (print_name[0] == '/' && l->name[0] != '/'))
     179  	print_name = l->name;
     180  
     181        if (fromlist != NULL)
     182  	result |= match_file (fromlist, l->name, strlen (l->name),
     183  			      LA_FLG_BINDFROM);
     184  
     185        if (tolist != NULL)
     186  	result |= match_file (tolist, l->name, strlen (l->name),LA_FLG_BINDTO);
     187      }
     188  
     189    if (print_name == NULL)
     190      print_name = base_name;
     191    if (print_name[0] == '\0')
     192      print_name = __progname;
     193  
     194    /* We cannot easily get to the object name in the PLT handling
     195       functions.  Use the cookie to get the string pointer passed back
     196       to us.  */
     197    *cookie = (uintptr_t) print_name;
     198  
     199    /* The object name has to be on the list of objects to trace calls
     200       from or that list must be empty.  In the latter case we trace
     201       only calls from the main binary.  */
     202    if (fromlist == NULL)
     203      result |= map->l_name[0] == '\0' ? LA_FLG_BINDFROM : 0;
     204    else
     205      result |= (match_file (fromlist, full_name, full_name_len,
     206  			   LA_FLG_BINDFROM)
     207  	       | match_file (fromlist, base_name, base_name_len,
     208  			     LA_FLG_BINDFROM));
     209  
     210    /* The object name has to be on the list of objects to trace calls
     211       to or that list must be empty.  In the latter case we trace
     212       calls toall objects.  */
     213    if (tolist == NULL)
     214      result |= LA_FLG_BINDTO;
     215    else
     216      result |= (match_file (tolist, full_name, full_name_len, LA_FLG_BINDTO)
     217  	       | match_file (tolist, base_name, base_name_len, LA_FLG_BINDTO));
     218  
     219    return result;
     220  }
     221  
     222  
     223  #if __ELF_NATIVE_CLASS == 32
     224  # define la_symbind la_symbind32
     225  typedef Elf32_Sym Elf_Sym;
     226  #else
     227  # define la_symbind la_symbind64
     228  typedef Elf64_Sym Elf_Sym;
     229  #endif
     230  
     231  uintptr_t
     232  la_symbind (Elf_Sym *sym, unsigned int ndx, uintptr_t *refcook,
     233  	    uintptr_t *defcook, unsigned int *flags, const char *symname)
     234  {
     235    if (*flags & LA_SYMB_NOPLTENTER)
     236      warnx ("cannot trace PLT enter (bind-now enabled)");
     237  
     238    if (do_exit && *flags & LA_SYMB_NOPLTEXIT)
     239      warnx ("cannot trace PLT exit (bind-now enabled)");
     240  
     241    if (!do_exit)
     242      *flags = LA_SYMB_NOPLTEXIT;
     243  
     244    return sym->st_value;
     245  }
     246  
     247  
     248  static void
     249  print_enter (uintptr_t *refcook, uintptr_t *defcook, const char *symname,
     250  	     unsigned long int reg1, unsigned long int reg2,
     251  	     unsigned long int reg3, unsigned int flags)
     252  {
     253    char buf[3 * sizeof (pid_t) + 3];
     254    buf[0] = '\0';
     255    if (print_pid)
     256      snprintf (buf, sizeof (buf), "%5ld: ", (long int) getpid ());
     257  
     258    fprintf (out_file, "%s%15s -> %-15s:%s%s(0x%lx, 0x%lx, 0x%lx)\n",
     259  	   buf, (char *) *refcook, (char *) *defcook,
     260  	   (flags & LA_SYMB_NOPLTEXIT) ? "*" : " ", symname, reg1, reg2, reg3);
     261  }
     262  
     263  
     264  #ifdef __i386__
     265  Elf32_Addr
     266  la_i86_gnu_pltenter (Elf32_Sym *sym __attribute__ ((unused)),
     267  		     unsigned int ndx __attribute__ ((unused)),
     268  		     uintptr_t *refcook, uintptr_t *defcook,
     269  		     La_i86_regs *regs, unsigned int *flags,
     270  		     const char *symname, long int *framesizep)
     271  {
     272    unsigned long int *sp = (unsigned long int *) regs->lr_esp;
     273  
     274    print_enter (refcook, defcook, symname, sp[1], sp[2], sp[3], *flags);
     275  
     276    /* No need to copy anything, we will not need the parameters in any case.  */
     277    *framesizep = 0;
     278  
     279    return sym->st_value;
     280  }
     281  #elif defined __x86_64__
     282  Elf64_Addr
     283  la_x86_64_gnu_pltenter (Elf64_Sym *sym __attribute__ ((unused)),
     284  			unsigned int ndx __attribute__ ((unused)),
     285  			uintptr_t *refcook, uintptr_t *defcook,
     286  			La_x86_64_regs *regs, unsigned int *flags,
     287  			const char *symname, long int *framesizep)
     288  {
     289    print_enter (refcook, defcook, symname,
     290  	       regs->lr_rdi, regs->lr_rsi, regs->lr_rdx, *flags);
     291  
     292    /* No need to copy anything, we will not need the parameters in any case.  */
     293    *framesizep = 0;
     294  
     295    return sym->st_value;
     296  }
     297  #elif defined __sparc__ && !defined __arch64__
     298  Elf32_Addr
     299  la_sparc32_gnu_pltenter (Elf32_Sym *sym __attribute__ ((unused)),
     300  			 unsigned int ndx __attribute__ ((unused)),
     301  			 uintptr_t *refcook, uintptr_t *defcook,
     302  			 La_sparc32_regs *regs, unsigned int *flags,
     303  			 const char *symname, long int *framesizep)
     304  {
     305    print_enter (refcook, defcook, symname,
     306  	       regs->lr_reg[0], regs->lr_reg[1], regs->lr_reg[2],
     307  	       *flags);
     308  
     309    /* No need to copy anything, we will not need the parameters in any case.  */
     310    *framesizep = 0;
     311  
     312    return sym->st_value;
     313  }
     314  #elif defined __sparc__ && defined __arch64__
     315  Elf64_Addr
     316  la_sparc64_gnu_pltenter (Elf64_Sym *sym __attribute__ ((unused)),
     317  			 unsigned int ndx __attribute__ ((unused)),
     318  			 uintptr_t *refcook, uintptr_t *defcook,
     319  			 La_sparc64_regs *regs, unsigned int *flags,
     320  			 const char *symname, long int *framesizep)
     321  {
     322    print_enter (refcook, defcook, symname,
     323  	       regs->lr_reg[0], regs->lr_reg[1], regs->lr_reg[2],
     324  	       *flags);
     325  
     326    /* No need to copy anything, we will not need the parameters in any case.  */
     327    *framesizep = 0;
     328  
     329    return sym->st_value;
     330  }
     331  #elif !defined HAVE_ARCH_PLTENTER
     332  # warning "pltenter for architecture not supported"
     333  #endif
     334  
     335  
     336  static void
     337  print_exit (uintptr_t *refcook, uintptr_t *defcook, const char *symname,
     338  	    unsigned long int reg)
     339  {
     340    char buf[3 * sizeof (pid_t) + 3];
     341    buf[0] = '\0';
     342    if (print_pid)
     343      snprintf (buf, sizeof (buf), "%5ld: ", (long int) getpid ());
     344  
     345    fprintf (out_file, "%s%15s -> %-15s:%s%s - 0x%lx\n",
     346  	   buf, (char *) *refcook, (char *) *defcook, " ", symname, reg);
     347  }
     348  
     349  
     350  #ifdef __i386__
     351  unsigned int
     352  la_i86_gnu_pltexit (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
     353  		    uintptr_t *defcook, const struct La_i86_regs *inregs,
     354  		    struct La_i86_retval *outregs, const char *symname)
     355  {
     356    print_exit (refcook, defcook, symname, outregs->lrv_eax);
     357  
     358    return 0;
     359  }
     360  #elif defined __x86_64__
     361  unsigned int
     362  la_x86_64_gnu_pltexit (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
     363  		       uintptr_t *defcook, const struct La_x86_64_regs *inregs,
     364  		       struct La_x86_64_retval *outregs, const char *symname)
     365  {
     366    print_exit (refcook, defcook, symname, outregs->lrv_rax);
     367  
     368    return 0;
     369  }
     370  #elif defined __sparc__ && !defined __arch64__
     371  unsigned int
     372  la_sparc32_gnu_pltexit (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
     373  			uintptr_t *defcook, const struct La_sparc32_regs *inregs,
     374  			struct La_sparc32_retval *outregs, const char *symname)
     375  {
     376    print_exit (refcook, defcook, symname, outregs->lrv_reg[0]);
     377  
     378    return 0;
     379  }
     380  #elif defined __sparc__ && defined __arch64__
     381  unsigned int
     382  la_sparc64_gnu_pltexit (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
     383  			uintptr_t *defcook, const struct La_sparc64_regs *inregs,
     384  			struct La_sparc64_retval *outregs, const char *symname)
     385  {
     386    print_exit (refcook, defcook, symname, outregs->lrv_reg[0]);
     387  
     388    return 0;
     389  }
     390  #elif !defined HAVE_ARCH_PLTEXIT
     391  # warning "pltexit for architecture not supported"
     392  #endif