/* * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl> * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl> * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com> * Copyright (c) 1996-2021 The strace developers. * All rights reserved. * * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "defs.h" #include "kernel_fcntl.h" #include <signal.h> #include <sys/timex.h> #if HAVE_ARCH_TIME32_SYSCALLS || HAVE_ARCH_OLD_TIME64_SYSCALLS static void print_timezone(struct tcb *const tcp, const kernel_ulong_t addr) { struct timezone tz; if (umove_or_printaddr(tcp, addr, &tz)) return; tprint_struct_begin(); PRINT_FIELD_D(tz, tz_minuteswest); tprint_struct_next(); PRINT_FIELD_D(tz, tz_dsttime); tprint_struct_end(); } SYS_FUNC(gettimeofday) { if (exiting(tcp)) { /* tv */ print_timeval(tcp, tcp->u_arg[0]); tprint_arg_next(); /* tz */ print_timezone(tcp, tcp->u_arg[1]); } return 0; } SYS_FUNC(settimeofday) { /* tv */ print_timeval(tcp, tcp->u_arg[0]); tprint_arg_next(); /* tz */ print_timezone(tcp, tcp->u_arg[1]); return RVAL_DECODED; } #endif #ifdef ALPHA SYS_FUNC(osf_gettimeofday) { if (exiting(tcp)) { /* tv */ print_timeval32(tcp, tcp->u_arg[0]); tprint_arg_next(); /* tz */ print_timezone(tcp, tcp->u_arg[1]); } return 0; } #endif #ifdef ALPHA SYS_FUNC(osf_settimeofday) { /* tv */ print_timeval32(tcp, tcp->u_arg[0]); tprint_arg_next(); /* tz */ print_timezone(tcp, tcp->u_arg[1]); return RVAL_DECODED; } #endif #if HAVE_ARCH_TIME32_SYSCALLS || HAVE_ARCH_OLD_TIME64_SYSCALLS static int do_nanosleep(struct tcb *const tcp, const print_obj_by_addr_fn print_ts) { if (entering(tcp)) { /* req */ print_ts(tcp, tcp->u_arg[0]); tprint_arg_next(); } else { /* rem */ /* * Second (returned) timespec is only significant if syscall * was interrupted. On success and in case of other errors we * print only its address, since kernel doesn't modify it, * and printing the value may show uninitialized data. */ if (is_erestart(tcp)) { temporarily_clear_syserror(tcp); print_ts(tcp, tcp->u_arg[1]); restore_cleared_syserror(tcp); } else { printaddr(tcp->u_arg[1]); } } return 0; } #endif /* HAVE_ARCH_TIME32_SYSCALLS || HAVE_ARCH_OLD_TIME64_SYSCALLS */ #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(nanosleep_time32) { return do_nanosleep(tcp, print_timespec32); } #endif #if HAVE_ARCH_OLD_TIME64_SYSCALLS SYS_FUNC(nanosleep_time64) { return do_nanosleep(tcp, print_timespec64); } #endif #include "xlat/itimer_which.h" SYS_FUNC(getitimer) { if (entering(tcp)) { /* which */ printxval(itimer_which, tcp->u_arg[0], "ITIMER_???"); tprint_arg_next(); } else { /* curr_value */ print_itimerval(tcp, tcp->u_arg[1]); } return 0; } #ifdef ALPHA SYS_FUNC(osf_getitimer) { if (entering(tcp)) { /* which */ printxval(itimer_which, tcp->u_arg[0], "ITIMER_???"); tprint_arg_next(); } else { /* curr_value */ print_itimerval32(tcp, tcp->u_arg[1]); } return 0; } #endif SYS_FUNC(setitimer) { if (entering(tcp)) { /* which */ printxval(itimer_which, tcp->u_arg[0], "ITIMER_???"); tprint_arg_next(); /* new_value */ print_itimerval(tcp, tcp->u_arg[1]); tprint_arg_next(); } else { /* old_value */ print_itimerval(tcp, tcp->u_arg[2]); } return 0; } #ifdef ALPHA SYS_FUNC(osf_setitimer) { if (entering(tcp)) { /* which */ printxval(itimer_which, tcp->u_arg[0], "ITIMER_???"); tprint_arg_next(); /* new_value */ print_itimerval32(tcp, tcp->u_arg[1]); tprint_arg_next(); } else { /* old_value */ print_itimerval32(tcp, tcp->u_arg[2]); } return 0; } #endif #include "xlat/adjtimex_state.h" static int do_adjtimex(struct tcb *const tcp, const print_obj_by_addr_fn print_tx, const kernel_ulong_t addr) { /* buf */ if (print_tx(tcp, addr)) return 0; tcp->auxstr = xlookup(adjtimex_state, (kernel_ulong_t) tcp->u_rval); return RVAL_STR; } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(adjtimex32) { if (exiting(tcp)) return do_adjtimex(tcp, print_timex32, tcp->u_arg[0]); return 0; } #endif #if HAVE_ARCH_OLD_TIME64_SYSCALLS SYS_FUNC(adjtimex64) { if (exiting(tcp)) # ifndef SPARC64 return do_adjtimex(tcp, print_timex64, tcp->u_arg[0]); # else return do_adjtimex(tcp, print_sparc64_timex, tcp->u_arg[0]); # endif return 0; } #endif #include "xlat/clockflags.h" #include "xlat/clocknames.h" static void printclockname(int clockid) { #ifdef CLOCKID_TO_FD # include "xlat/cpuclocknames.h" if (clockid < 0) { if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV) PRINT_VAL_D(clockid); if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW) return; if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE) tprint_comment_begin(); if ((clockid & CLOCKFD_MASK) == CLOCKFD) tprints_arg_begin("FD_TO_CLOCKID"); PRINT_VAL_D(CLOCKID_TO_FD(clockid)); else { tprints_arg_begin(CPUCLOCK_PERTHREAD(clockid) ? "MAKE_THREAD_CPUCLOCK" : "MAKE_PROCESS_CPUCLOCK"); PRINT_VAL_D(CPUCLOCK_PID(clockid)); tprint_arg_next(); printxval(cpuclocknames, clockid & CLOCKFD_MASK, "CPUCLOCK_???"); } tprint_arg_end(); if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE) tprint_comment_end(); } else #endif printxval(clocknames, clockid, "CLOCK_???"); } static int do_clock_settime(struct tcb *const tcp, const print_obj_by_addr_fn print_ts) { /* clockid */ printclockname(tcp->u_arg[0]); tprint_arg_next(); /* tp */ print_ts(tcp, tcp->u_arg[1]); return RVAL_DECODED; } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(clock_settime32) { return do_clock_settime(tcp, print_timespec32); } #endif SYS_FUNC(clock_settime64) { return do_clock_settime(tcp, print_timespec64); } static int do_clock_gettime(struct tcb *const tcp, const print_obj_by_addr_fn print_ts) { if (entering(tcp)) { /* clockid */ printclockname(tcp->u_arg[0]); tprint_arg_next(); } else { /* tp */ print_ts(tcp, tcp->u_arg[1]); } return 0; } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(clock_gettime32) { return do_clock_gettime(tcp, print_timespec32); } #endif SYS_FUNC(clock_gettime64) { return do_clock_gettime(tcp, print_timespec64); } static int do_clock_nanosleep(struct tcb *const tcp, const print_obj_by_addr_fn print_ts) { if (entering(tcp)) { /* clockid */ printclockname(tcp->u_arg[0]); tprint_arg_next(); /* flags */ printflags(clockflags, tcp->u_arg[1], "TIMER_???"); tprint_arg_next(); /* request */ print_ts(tcp, tcp->u_arg[2]); tprint_arg_next(); } else { /* remain */ /* * Second (returned) timespec is only significant * if syscall was interrupted and flags is not TIMER_ABSTIME. */ if (!tcp->u_arg[1] && is_erestart(tcp)) { temporarily_clear_syserror(tcp); print_ts(tcp, tcp->u_arg[3]); restore_cleared_syserror(tcp); } else { printaddr(tcp->u_arg[3]); } } return 0; } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(clock_nanosleep_time32) { return do_clock_nanosleep(tcp, print_timespec32); } #endif SYS_FUNC(clock_nanosleep_time64) { return do_clock_nanosleep(tcp, print_timespec64); } static int do_clock_adjtime(struct tcb *const tcp, const print_obj_by_addr_fn print_tx) { if (entering(tcp)) { /* clockid */ printclockname(tcp->u_arg[0]); tprint_arg_next(); return 0; } else { return do_adjtimex(tcp, print_tx, tcp->u_arg[1]); } } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(clock_adjtime32) { return do_clock_adjtime(tcp, print_timex32); } #endif SYS_FUNC(clock_adjtime64) { return do_clock_adjtime(tcp, print_timex64); } #ifdef SPARC64 SYS_FUNC(clock_sparc64_adjtime) { return do_clock_adjtime(tcp, print_sparc64_timex); } #endif SYS_FUNC(timer_create) { if (entering(tcp)) { /* clockid */ printclockname(tcp->u_arg[0]); tprint_arg_next(); /* sevp */ print_sigevent(tcp, tcp->u_arg[1]); tprint_arg_next(); } else { /* timerid */ printnum_int(tcp, tcp->u_arg[2], "%d"); } return 0; } static int do_timer_settime(struct tcb *const tcp, const print_obj_by_addr_fn print_its) { if (entering(tcp)) { /* timerid */ PRINT_VAL_D((int) tcp->u_arg[0]); tprint_arg_next(); /* flags */ printflags(clockflags, tcp->u_arg[1], "TIMER_???"); tprint_arg_next(); /* new_value */ print_its(tcp, tcp->u_arg[2]); tprint_arg_next(); } else { /* old_value */ print_its(tcp, tcp->u_arg[3]); } return 0; } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(timer_settime32) { return do_timer_settime(tcp, print_itimerspec32); } #endif SYS_FUNC(timer_settime64) { return do_timer_settime(tcp, print_itimerspec64); } static int do_timer_gettime(struct tcb *const tcp, const print_obj_by_addr_fn print_its) { if (entering(tcp)) { /* timerid */ PRINT_VAL_D((int) tcp->u_arg[0]); tprint_arg_next(); } else { /* curr_value */ print_its(tcp, tcp->u_arg[1]); } return 0; } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(timer_gettime32) { return do_timer_gettime(tcp, print_itimerspec32); } #endif SYS_FUNC(timer_gettime64) { return do_timer_gettime(tcp, print_itimerspec64); } #include "xlat/timerfdflags.h" SYS_FUNC(timerfd_create) { /* clockid */ printclockname(tcp->u_arg[0]); tprint_arg_next(); /* flags */ printflags(timerfdflags, tcp->u_arg[1], "TFD_???"); return RVAL_DECODED | RVAL_FD; } static int do_timerfd_settime(struct tcb *const tcp, const print_obj_by_addr_fn print_its) { if (entering(tcp)) { /* fd */ printfd(tcp, tcp->u_arg[0]); tprint_arg_next(); /* flags */ printflags(timerfdflags, tcp->u_arg[1], "TFD_???"); tprint_arg_next(); /* new_value */ print_its(tcp, tcp->u_arg[2]); tprint_arg_next(); } else { /* old_value */ print_its(tcp, tcp->u_arg[3]); } return 0; } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(timerfd_settime32) { return do_timerfd_settime(tcp, print_itimerspec32); } #endif SYS_FUNC(timerfd_settime64) { return do_timerfd_settime(tcp, print_itimerspec64); } static int do_timerfd_gettime(struct tcb *const tcp, const print_obj_by_addr_fn print_its) { if (entering(tcp)) { /* fd */ printfd(tcp, tcp->u_arg[0]); tprint_arg_next(); } else { /* curr_value */ print_its(tcp, tcp->u_arg[1]); } return 0; } #if HAVE_ARCH_TIME32_SYSCALLS SYS_FUNC(timerfd_gettime32) { return do_timerfd_gettime(tcp, print_itimerspec32); } #endif SYS_FUNC(timerfd_gettime64) { return do_timerfd_gettime(tcp, print_itimerspec64); }