(root)/
strace-6.5/
src/
desc.c
       1  /*
       2   * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
       3   * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
       4   * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
       5   * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
       6   * Copyright (c) 1999-2021 The strace developers.
       7   * All rights reserved.
       8   *
       9   * SPDX-License-Identifier: LGPL-2.1-or-later
      10   */
      11  
      12  #include "defs.h"
      13  #include "xstring.h"
      14  
      15  SYS_FUNC(close)
      16  {
      17  	printfd(tcp, tcp->u_arg[0]);
      18  
      19  	return RVAL_DECODED;
      20  }
      21  
      22  static int
      23  decode_select(struct tcb *const tcp, const kernel_ulong_t *const args,
      24  	      const print_obj_by_addr_fn print_tv_ts,
      25  	      const sprint_obj_by_addr_fn sprint_tv_ts)
      26  {
      27  	/* Kernel truncates args[0] to int, we do the same. */
      28  	int nfds = (int) args[0];
      29  
      30  	/* Kernel rejects negative nfds, so we don't parse it either. */
      31  	if (nfds < 0)
      32  		nfds = 0;
      33  
      34  	/* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
      35  	if (nfds > 1024*1024)
      36  		nfds = 1024*1024;
      37  
      38  	/*
      39  	 * We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below.
      40  	 * Instead of args[0], use nfds for fd count, fdsize for array lengths.
      41  	 */
      42  	int fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
      43  	fd_set *fds = NULL;
      44  
      45  	if (entering(tcp)) {
      46  		PRINT_VAL_D((int) args[0]);
      47  
      48  		if (verbose(tcp) && fdsize > 0)
      49  			fds = malloc(fdsize);
      50  		for (unsigned int i = 0; i < 3; ++i) {
      51  			kernel_ulong_t addr = args[i + 1];
      52  
      53  			tprint_arg_next();
      54  			if (!fds) {
      55  				printaddr(addr);
      56  				continue;
      57  			}
      58  			if (umoven_or_printaddr(tcp, addr, fdsize, fds))
      59  				continue;
      60  			tprint_bitset_begin();
      61  			bool next = false;
      62  			for (int j = 0;; ++j) {
      63  				j = next_set_bit(fds, j, nfds);
      64  				if (j < 0)
      65  					break;
      66  				if (next)
      67  					tprint_bitset_next();
      68  				else
      69  					next = true;
      70  				printfd(tcp, j);
      71  			}
      72  			tprint_bitset_end();
      73  		}
      74  		free(fds);
      75  		tprint_arg_next();
      76  		print_tv_ts(tcp, args[4]);
      77  	} else {
      78  		static char outstr[1024];
      79  		char *outptr;
      80  #define end_outstr (outstr + sizeof(outstr))
      81  		int ready_fds;
      82  
      83  		if (syserror(tcp))
      84  			return 0;
      85  
      86  		ready_fds = tcp->u_rval;
      87  		if (ready_fds == 0) {
      88  			tcp->auxstr = "Timeout";
      89  			return RVAL_STR;
      90  		}
      91  
      92  		fds = malloc(fdsize);
      93  
      94  		outptr = outstr;
      95  		const char *sep = "";
      96  		for (unsigned int i = 0; i < 3 && ready_fds > 0; ++i) {
      97  			int first = 1;
      98  			kernel_ulong_t addr = args[i + 1];
      99  
     100  			if (!addr || !fds || umoven(tcp, addr, fdsize, fds) < 0)
     101  				continue;
     102  			for (int j = 0;; ++j) {
     103  				j = next_set_bit(fds, j, nfds);
     104  				if (j < 0)
     105  					break;
     106  				/* +2 chars needed at the end: ']',NUL */
     107  				if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) {
     108  					if (first) {
     109  						outptr = xappendstr(outstr,
     110  							outptr,
     111  							"%s%s [%u",
     112  							sep,
     113  							i == 0 ? "in" : i == 1 ? "out" : "except",
     114  							j
     115  						);
     116  						first = 0;
     117  						sep = ", ";
     118  					} else {
     119  						outptr = xappendstr(outstr,
     120  							outptr,
     121  							" %u", j);
     122  					}
     123  				}
     124  				if (--ready_fds == 0)
     125  					break;
     126  			}
     127  			if (outptr != outstr)
     128  				*outptr++ = ']';
     129  		}
     130  		free(fds);
     131  		/* This contains no useful information on SunOS.  */
     132  		if (args[4]) {
     133  			const char *str = sprint_tv_ts(tcp, args[4]);
     134  			if (outptr + sizeof("left ") + strlen(sep) + strlen(str) < end_outstr) {
     135  				outptr = xappendstr(outstr, outptr,
     136  						    "%sleft %s", sep, str);
     137  			}
     138  		}
     139  		*outptr = '\0';
     140  		tcp->auxstr = outstr;
     141  		return RVAL_STR;
     142  #undef end_outstr
     143  	}
     144  	return 0;
     145  }
     146  
     147  #if HAVE_ARCH_OLD_SELECT
     148  SYS_FUNC(oldselect)
     149  {
     150  	kernel_ulong_t *args =
     151  		fetch_indirect_syscall_args(tcp, tcp->u_arg[0], 5);
     152  
     153  	if (args) {
     154  		return decode_select(tcp, args, print_timeval, sprint_timeval);
     155  	} else {
     156  		if (entering(tcp))
     157  			printaddr(tcp->u_arg[0]);
     158  		return RVAL_DECODED;
     159  	}
     160  }
     161  #endif /* HAVE_ARCH_OLD_SELECT */
     162  
     163  #ifdef ALPHA
     164  SYS_FUNC(osf_select)
     165  {
     166  	return decode_select(tcp, tcp->u_arg, print_timeval32, sprint_timeval32);
     167  }
     168  #endif
     169  
     170  SYS_FUNC(select)
     171  {
     172  	return decode_select(tcp, tcp->u_arg, print_timeval, sprint_timeval);
     173  }
     174  
     175  static int
     176  do_pselect6(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
     177  	    const sprint_obj_by_addr_fn sprint_ts)
     178  {
     179  	int rc = decode_select(tcp, tcp->u_arg, print_ts, sprint_ts);
     180  	if (entering(tcp)) {
     181  		tprint_arg_next();
     182  		print_kernel_sigset(tcp, tcp->u_arg[5]);
     183  	}
     184  
     185  	return rc;
     186  }
     187  
     188  #if HAVE_ARCH_TIME32_SYSCALLS
     189  SYS_FUNC(pselect6_time32)
     190  {
     191  	return do_pselect6(tcp, print_timespec32, sprint_timespec32);
     192  }
     193  #endif
     194  
     195  SYS_FUNC(pselect6_time64)
     196  {
     197  	return do_pselect6(tcp, print_timespec64, sprint_timespec64);
     198  }