(root)/
strace-6.5/
src/
poll.c
       1  /*
       2   * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
       3   * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
       4   * Copyright (c) 1999-2021 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: LGPL-2.1-or-later
       8   */
       9  
      10  #include "defs.h"
      11  #include <poll.h>
      12  #include "xstring.h"
      13  
      14  #include "xlat/pollflags.h"
      15  
      16  static bool
      17  print_pollfd(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
      18  {
      19  	const struct pollfd *fds = elem_buf;
      20  
      21  	tprint_struct_begin();
      22  	PRINT_FIELD_FD(*fds, fd, tcp);
      23  	if (fds->fd >= 0) {
      24  		tprint_struct_next();
      25  		PRINT_FIELD_FLAGS(*fds, events, pollflags, "POLL???");
      26  	}
      27  	tprint_struct_end();
      28  
      29  	return true;
      30  }
      31  
      32  static void
      33  decode_poll_entering(struct tcb *tcp)
      34  {
      35  	const kernel_ulong_t addr = tcp->u_arg[0];
      36  	const unsigned int nfds = tcp->u_arg[1];
      37  	struct pollfd fds;
      38  
      39  	/* fds */
      40  	print_array(tcp, addr, nfds, &fds, sizeof(fds),
      41  		    tfetch_mem, print_pollfd, 0);
      42  	tprint_arg_next();
      43  
      44  	/* nfds */
      45  	PRINT_VAL_U(nfds);
      46  	tprint_arg_next();
      47  }
      48  
      49  static int
      50  decode_poll_exiting(struct tcb *const tcp, const sprint_obj_by_addr_fn sprint_ts,
      51  		    const kernel_ulong_t pts)
      52  {
      53  	struct pollfd fds;
      54  	const unsigned int nfds = tcp->u_arg[1];
      55  	const unsigned long size = sizeof(fds) * nfds;
      56  	const kernel_ulong_t start = tcp->u_arg[0];
      57  	const kernel_ulong_t end = start + size;
      58  	const unsigned int max_printed =
      59  		abbrev(tcp) ? max_strlen : -1U;
      60  	unsigned int printed = 0;
      61  
      62  	static char outstr[1024];
      63  	char *outptr;
      64  #define end_outstr (outstr + sizeof(outstr))
      65  
      66  	if (syserror(tcp))
      67  		return 0;
      68  	if (tcp->u_rval == 0) {
      69  		tcp->auxstr = "Timeout";
      70  		return RVAL_STR;
      71  	}
      72  
      73  	if (!verbose(tcp) || !start || !nfds ||
      74  	    size / sizeof(fds) != nfds || end < start)
      75  		return 0;
      76  
      77  	outptr = outstr;
      78  
      79  	for (kernel_ulong_t cur = start; cur < end; cur += sizeof(fds)) {
      80  		if (umove(tcp, cur, &fds) < 0) {
      81  			if (outptr == outstr)
      82  				*outptr++ = '[';
      83  			else
      84  				outptr = stpcpy(outptr, ", ");
      85  			outptr = xappendstr(outstr, outptr, "%#" PRI_klx, cur);
      86  			break;
      87  		}
      88  		if (!fds.revents)
      89  			continue;
      90  		if (outptr == outstr)
      91  			*outptr++ = '[';
      92  		else
      93  			outptr = stpcpy(outptr, ", ");
      94  		if (printed >= max_printed) {
      95  			outptr = stpcpy(outptr, "...");
      96  			break;
      97  		}
      98  
      99  		static const char fmt[] = "{fd=%d, revents=";
     100  		char fdstr[sizeof(fmt) + sizeof(int) * 3];
     101  		xsprintf(fdstr, fmt, fds.fd);
     102  
     103  		const char *flagstr = sprintflags("", pollflags,
     104  						  (unsigned short) fds.revents);
     105  
     106  		if (outptr + strlen(fdstr) + strlen(flagstr) + 1 >=
     107  		    end_outstr - (2 + 2 * sizeof(long) + sizeof(", ], ..."))) {
     108  			outptr = stpcpy(outptr, "...");
     109  			break;
     110  		}
     111  		outptr = stpcpy(outptr, fdstr);
     112  		outptr = stpcpy(outptr, flagstr);
     113  		*outptr++ = '}';
     114  		++printed;
     115  	}
     116  
     117  	if (outptr != outstr)
     118  		*outptr++ = ']';
     119  
     120  	*outptr = '\0';
     121  	if (pts) {
     122  		const char *str = sprint_ts(tcp, pts);
     123  
     124  		if (outptr + sizeof(", left ") + strlen(str) < end_outstr) {
     125  			outptr = stpcpy(outptr, outptr == outstr ? "left " : ", left ");
     126  			outptr = stpcpy(outptr, str);
     127  		} else {
     128  			outptr = stpcpy(outptr, ", ...");
     129  		}
     130  	}
     131  
     132  	if (outptr == outstr)
     133  		return 0;
     134  
     135  	tcp->auxstr = outstr;
     136  	return RVAL_STR;
     137  #undef end_outstr
     138  }
     139  
     140  #if HAVE_ARCH_TIME32_SYSCALLS || HAVE_ARCH_OLD_TIME64_SYSCALLS
     141  static int
     142  do_poll(struct tcb *const tcp, const sprint_obj_by_addr_fn sprint_ts)
     143  {
     144  	if (entering(tcp)) {
     145  		decode_poll_entering(tcp);
     146  
     147  		/* timeout */
     148  		PRINT_VAL_D((int) tcp->u_arg[2]);
     149  
     150  		return 0;
     151  	} else {
     152  		return decode_poll_exiting(tcp, sprint_ts, 0);
     153  	}
     154  }
     155  #endif /* HAVE_ARCH_TIME32_SYSCALLS || HAVE_ARCH_OLD_TIME64_SYSCALLS */
     156  
     157  #if HAVE_ARCH_TIME32_SYSCALLS
     158  SYS_FUNC(poll_time32)
     159  {
     160  	return do_poll(tcp, sprint_timespec32);
     161  }
     162  #endif
     163  
     164  #if HAVE_ARCH_OLD_TIME64_SYSCALLS
     165  SYS_FUNC(poll_time64)
     166  {
     167  	return do_poll(tcp, sprint_timespec64);
     168  }
     169  #endif
     170  
     171  static int
     172  do_ppoll(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
     173  	 const sprint_obj_by_addr_fn sprint_ts)
     174  {
     175  	if (entering(tcp)) {
     176  		decode_poll_entering(tcp);
     177  
     178  		/* tmo_p */
     179  		print_ts(tcp, tcp->u_arg[2]);
     180  		tprint_arg_next();
     181  
     182  		/* sigmask */
     183  		/* NB: kernel requires arg[4] == NSIG_BYTES */
     184  		print_sigset_addr_len(tcp, tcp->u_arg[3], tcp->u_arg[4]);
     185  		tprint_arg_next();
     186  
     187  		/* sigsetsize */
     188  		PRINT_VAL_U(tcp->u_arg[4]);
     189  
     190  		return 0;
     191  	} else {
     192  		return decode_poll_exiting(tcp, sprint_ts, tcp->u_arg[2]);
     193  	}
     194  }
     195  
     196  #if HAVE_ARCH_TIME32_SYSCALLS
     197  SYS_FUNC(ppoll_time32)
     198  {
     199  	return do_ppoll(tcp, print_timespec32, sprint_timespec32);
     200  }
     201  #endif
     202  
     203  SYS_FUNC(ppoll_time64)
     204  {
     205  	return do_ppoll(tcp, print_timespec64, sprint_timespec64);
     206  }