]> granicus.if.org Git - strace/blob - time.c
Fix ioctl entries on 32-bit architectures with 64-bit aligned structures
[strace] / time.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  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "defs.h"
31 #include <fcntl.h>
32 #include <linux/version.h>
33 #include <sys/timex.h>
34 #include <linux/ioctl.h>
35 #include <linux/rtc.h>
36
37 #ifndef UTIME_NOW
38 #define UTIME_NOW ((1l << 30) - 1l)
39 #endif
40 #ifndef UTIME_OMIT
41 #define UTIME_OMIT ((1l << 30) - 2l)
42 #endif
43
44 #if SUPPORTED_PERSONALITIES > 1
45 # if defined X86_64 || defined X32
46 #  define current_time_t_is_compat (current_personality == 1)
47 # else
48 #  define current_time_t_is_compat (current_wordsize == 4)
49 # endif
50 #else
51 # define current_time_t_is_compat 0
52 #endif
53
54 struct timeval32
55 {
56         u_int32_t tv_sec, tv_usec;
57 };
58
59 static void
60 tprint_timeval32(struct tcb *tcp, const struct timeval32 *tv)
61 {
62         tprintf("{%u, %u}", tv->tv_sec, tv->tv_usec);
63 }
64
65 static void
66 tprint_timeval(struct tcb *tcp, const struct timeval *tv)
67 {
68         tprintf("{%ju, %ju}", (uintmax_t) tv->tv_sec, (uintmax_t) tv->tv_usec);
69 }
70
71 void
72 printtv_bitness(struct tcb *tcp, long addr, enum bitness_t bitness, int special)
73 {
74         char buf[TIMEVAL_TEXT_BUFSIZE];
75         sprinttv(buf, tcp, addr, bitness, special);
76         tprints(buf);
77 }
78
79 static char *
80 do_sprinttv(char *buf, const uintmax_t sec, const uintmax_t usec,
81             const int special)
82 {
83         if (special) {
84                 switch (usec) {
85                         case UTIME_NOW:
86                                 return stpcpy(buf, "UTIME_NOW");
87                         case UTIME_OMIT:
88                                 return stpcpy(buf, "UTIME_OMIT");
89                 }
90         }
91         return buf + sprintf(buf, "{%ju, %ju}", sec, usec);
92 }
93
94 char *
95 sprinttv(char *buf, struct tcb *tcp, long addr, enum bitness_t bitness, int special)
96 {
97         if (addr == 0)
98                 return stpcpy(buf, "NULL");
99
100         if (!verbose(tcp))
101                 return buf + sprintf(buf, "%#lx", addr);
102
103         if (bitness == BITNESS_32 || current_time_t_is_compat)
104         {
105                 struct timeval32 tv;
106
107                 if (umove(tcp, addr, &tv) >= 0)
108                         return do_sprinttv(buf, tv.tv_sec, tv.tv_usec, special);
109         } else {
110                 struct timeval tv;
111
112                 if (umove(tcp, addr, &tv) >= 0)
113                         return do_sprinttv(buf, tv.tv_sec, tv.tv_usec, special);
114         }
115
116         return stpcpy(buf, "{...}");
117 }
118
119 void
120 print_timespec(struct tcb *tcp, long addr)
121 {
122         char buf[TIMESPEC_TEXT_BUFSIZE];
123         sprint_timespec(buf, tcp, addr);
124         tprints(buf);
125 }
126
127 void
128 sprint_timespec(char *buf, struct tcb *tcp, long addr)
129 {
130         if (addr == 0)
131                 strcpy(buf, "NULL");
132         else if (!verbose(tcp))
133                 sprintf(buf, "%#lx", addr);
134         else {
135                 int rc;
136
137 #if SUPPORTED_PERSONALITIES > 1
138                 if (current_time_t_is_compat) {
139                         struct timeval32 tv;
140
141                         rc = umove(tcp, addr, &tv);
142                         if (rc >= 0)
143                                 sprintf(buf, "{%u, %u}",
144                                         tv.tv_sec, tv.tv_usec);
145                 } else
146 #endif
147                 {
148                         struct timespec ts;
149
150                         rc = umove(tcp, addr, &ts);
151                         if (rc >= 0)
152                                 sprintf(buf, "{%ju, %ju}",
153                                         (uintmax_t) ts.tv_sec,
154                                         (uintmax_t) ts.tv_nsec);
155                 }
156                 if (rc < 0)
157                         strcpy(buf, "{...}");
158         }
159 }
160
161 SYS_FUNC(time)
162 {
163         if (exiting(tcp)) {
164                 printnum_long(tcp, tcp->u_arg[0], "%ld");
165         }
166         return 0;
167 }
168
169 SYS_FUNC(gettimeofday)
170 {
171         if (exiting(tcp)) {
172                 if (syserror(tcp)) {
173                         tprintf("%#lx, %#lx", tcp->u_arg[0], tcp->u_arg[1]);
174                         return 0;
175                 }
176                 printtv(tcp, tcp->u_arg[0]);
177                 tprints(", ");
178                 printtv(tcp, tcp->u_arg[1]);
179         }
180         return 0;
181 }
182
183 #ifdef ALPHA
184 SYS_FUNC(osf_gettimeofday)
185 {
186         if (exiting(tcp)) {
187                 if (syserror(tcp)) {
188                         tprintf("%#lx, %#lx", tcp->u_arg[0], tcp->u_arg[1]);
189                         return 0;
190                 }
191                 printtv_bitness(tcp, tcp->u_arg[0], BITNESS_32, 0);
192                 tprints(", ");
193                 printtv_bitness(tcp, tcp->u_arg[1], BITNESS_32, 0);
194         }
195         return 0;
196 }
197 #endif
198
199 SYS_FUNC(settimeofday)
200 {
201         if (entering(tcp)) {
202                 printtv(tcp, tcp->u_arg[0]);
203                 tprints(", ");
204                 printtv(tcp, tcp->u_arg[1]);
205         }
206         return 0;
207 }
208
209 #ifdef ALPHA
210 SYS_FUNC(osf_settimeofday)
211 {
212         if (entering(tcp)) {
213                 printtv_bitness(tcp, tcp->u_arg[0], BITNESS_32, 0);
214                 tprints(", ");
215                 printtv_bitness(tcp, tcp->u_arg[1], BITNESS_32, 0);
216         }
217         return 0;
218 }
219 #endif
220
221 SYS_FUNC(adjtime)
222 {
223         if (entering(tcp)) {
224                 printtv(tcp, tcp->u_arg[0]);
225                 tprints(", ");
226         } else {
227                 if (syserror(tcp))
228                         tprintf("%#lx", tcp->u_arg[1]);
229                 else
230                         printtv(tcp, tcp->u_arg[1]);
231         }
232         return 0;
233 }
234
235 SYS_FUNC(nanosleep)
236 {
237         if (entering(tcp)) {
238                 print_timespec(tcp, tcp->u_arg[0]);
239                 tprints(", ");
240         } else {
241                 /* Second (returned) timespec is only significant
242                  * if syscall was interrupted. On success, we print
243                  * only its address, since kernel doesn't modify it,
244                  * and printing the value may show uninitialized data.
245                  */
246                 switch (tcp->u_error) {
247                 default:
248                         /* Not interrupted (slept entire interval) */
249                         if (tcp->u_arg[1]) {
250                                 tprintf("%#lx", tcp->u_arg[1]);
251                                 break;
252                         }
253                         /* Fall through: print_timespec(NULL) prints "NULL" */
254                 case ERESTARTSYS:
255                 case ERESTARTNOINTR:
256                 case ERESTARTNOHAND:
257                 case ERESTART_RESTARTBLOCK:
258                         /* Interrupted */
259                         print_timespec(tcp, tcp->u_arg[1]);
260                 }
261         }
262         return 0;
263 }
264
265 #include "xlat/itimer_which.h"
266
267 static void
268 printitv_bitness(struct tcb *tcp, long addr, enum bitness_t bitness)
269 {
270         if (addr == 0)
271                 tprints("NULL");
272         else if (!verbose(tcp))
273                 tprintf("%#lx", addr);
274         else {
275                 int rc;
276
277                 if (bitness == BITNESS_32 || current_time_t_is_compat) {
278                         struct {
279                                 struct timeval32 it_interval, it_value;
280                         } itv;
281
282                         rc = umove(tcp, addr, &itv);
283                         if (rc >= 0) {
284                                 tprints("{it_interval=");
285                                 tprint_timeval32(tcp, &itv.it_interval);
286                                 tprints(", it_value=");
287                                 tprint_timeval32(tcp, &itv.it_value);
288                                 tprints("}");
289                         }
290                 } else {
291                         struct itimerval itv;
292
293                         rc = umove(tcp, addr, &itv);
294                         if (rc >= 0) {
295                                 tprints("{it_interval=");
296                                 tprint_timeval(tcp, &itv.it_interval);
297                                 tprints(", it_value=");
298                                 tprint_timeval(tcp, &itv.it_value);
299                                 tprints("}");
300                         }
301                 }
302                 if (rc < 0)
303                         tprints("{...}");
304         }
305 }
306
307 #define printitv(tcp, addr)     \
308         printitv_bitness((tcp), (addr), BITNESS_CURRENT)
309
310 SYS_FUNC(getitimer)
311 {
312         if (entering(tcp)) {
313                 printxval(itimer_which, tcp->u_arg[0], "ITIMER_???");
314                 tprints(", ");
315         } else {
316                 if (syserror(tcp))
317                         tprintf("%#lx", tcp->u_arg[1]);
318                 else
319                         printitv(tcp, tcp->u_arg[1]);
320         }
321         return 0;
322 }
323
324 #ifdef ALPHA
325 SYS_FUNC(osf_getitimer)
326 {
327         if (entering(tcp)) {
328                 printxval(itimer_which, tcp->u_arg[0], "ITIMER_???");
329                 tprints(", ");
330         } else {
331                 if (syserror(tcp))
332                         tprintf("%#lx", tcp->u_arg[1]);
333                 else
334                         printitv_bitness(tcp, tcp->u_arg[1], BITNESS_32);
335         }
336         return 0;
337 }
338 #endif
339
340 SYS_FUNC(setitimer)
341 {
342         if (entering(tcp)) {
343                 printxval(itimer_which, tcp->u_arg[0], "ITIMER_???");
344                 tprints(", ");
345                 printitv(tcp, tcp->u_arg[1]);
346                 tprints(", ");
347         } else {
348                 if (syserror(tcp))
349                         tprintf("%#lx", tcp->u_arg[2]);
350                 else
351                         printitv(tcp, tcp->u_arg[2]);
352         }
353         return 0;
354 }
355
356 #ifdef ALPHA
357 SYS_FUNC(osf_setitimer)
358 {
359         if (entering(tcp)) {
360                 printxval(itimer_which, tcp->u_arg[0], "ITIMER_???");
361                 tprints(", ");
362                 printitv_bitness(tcp, tcp->u_arg[1], BITNESS_32);
363                 tprints(", ");
364         } else {
365                 if (syserror(tcp))
366                         tprintf("%#lx", tcp->u_arg[2]);
367                 else
368                         printitv_bitness(tcp, tcp->u_arg[2], BITNESS_32);
369         }
370         return 0;
371 }
372 #endif
373
374 #include "xlat/adjtimex_modes.h"
375 #include "xlat/adjtimex_status.h"
376 #include "xlat/adjtimex_state.h"
377
378 #if SUPPORTED_PERSONALITIES > 1
379 static int
380 tprint_timex32(struct tcb *tcp, long addr)
381 {
382         struct {
383                 unsigned int modes;
384                 int     offset;
385                 int     freq;
386                 int     maxerror;
387                 int     esterror;
388                 int     status;
389                 int     constant;
390                 int     precision;
391                 int     tolerance;
392                 struct timeval32 time;
393                 int     tick;
394                 int     ppsfreq;
395                 int     jitter;
396                 int     shift;
397                 int     stabil;
398                 int     jitcnt;
399                 int     calcnt;
400                 int     errcnt;
401                 int     stbcnt;
402         } tx;
403
404         if (umove(tcp, addr, &tx) < 0)
405                 return -1;
406
407         tprints("{modes=");
408         printflags(adjtimex_modes, tx.modes, "ADJ_???");
409         tprintf(", offset=%d, freq=%d, maxerror=%d, ",
410                 tx.offset, tx.freq, tx.maxerror);
411         tprintf("esterror=%u, status=", tx.esterror);
412         printflags(adjtimex_status, tx.status, "STA_???");
413         tprintf(", constant=%d, precision=%u, ",
414                 tx.constant, tx.precision);
415         tprintf("tolerance=%d, time=", tx.tolerance);
416         tprint_timeval32(tcp, &tx.time);
417         tprintf(", tick=%d, ppsfreq=%d, jitter=%d",
418                 tx.tick, tx.ppsfreq, tx.jitter);
419         tprintf(", shift=%d, stabil=%d, jitcnt=%d",
420                 tx.shift, tx.stabil, tx.jitcnt);
421         tprintf(", calcnt=%d, errcnt=%d, stbcnt=%d",
422                 tx.calcnt, tx.errcnt, tx.stbcnt);
423         tprints("}");
424         return 0;
425 }
426 #endif /* SUPPORTED_PERSONALITIES > 1 */
427
428 static int
429 tprint_timex(struct tcb *tcp, long addr)
430 {
431         struct timex tx;
432
433 #if SUPPORTED_PERSONALITIES > 1
434         if (current_time_t_is_compat)
435                 return tprint_timex32(tcp, addr);
436 #endif
437         if (umove(tcp, addr, &tx) < 0)
438                 return -1;
439
440 #if LINUX_VERSION_CODE < 66332
441         tprintf("{mode=%d, offset=%ld, frequency=%ld, ",
442                 tx.mode, tx.offset, tx.frequency);
443         tprintf("maxerror=%ld, esterror=%lu, status=%u, ",
444                 tx.maxerror, tx.esterror, tx.status);
445         tprintf("time_constant=%ld, precision=%lu, ",
446                 tx.time_constant, tx.precision);
447         tprintf("tolerance=%ld, time=", tx.tolerance);
448         tprint_timeval(tcp, &tx.time);
449 #else
450         tprints("{modes=");
451         printflags(adjtimex_modes, tx.modes, "ADJ_???");
452         tprintf(", offset=%jd, freq=%jd, maxerror=%ju, esterror=%ju, status=",
453                 (intmax_t) tx.offset, (intmax_t) tx.freq,
454                 (uintmax_t) tx.maxerror, (uintmax_t) tx.esterror);
455         printflags(adjtimex_status, tx.status, "STA_???");
456         tprintf(", constant=%jd, precision=%ju, tolerance=%jd, time=",
457                 (intmax_t) tx.constant, (uintmax_t) tx.precision,
458                 (intmax_t) tx.tolerance);
459         tprint_timeval(tcp, &tx.time);
460         tprintf(", tick=%jd, ppsfreq=%jd, jitter=%jd",
461                 (intmax_t) tx.tick, (intmax_t) tx.ppsfreq, (intmax_t) tx.jitter);
462         tprintf(", shift=%d, stabil=%jd, jitcnt=%jd",
463                 tx.shift, (intmax_t) tx.stabil, (intmax_t) tx.jitcnt);
464         tprintf(", calcnt=%jd, errcnt=%jd, stbcnt=%jd",
465                 (intmax_t) tx.calcnt, (intmax_t) tx.errcnt, (intmax_t) tx.stbcnt);
466 #endif
467         tprints("}");
468         return 0;
469 }
470
471 static int
472 do_adjtimex(struct tcb *tcp, long addr)
473 {
474         if (addr == 0)
475                 tprints("NULL");
476         else if (syserror(tcp) || !verbose(tcp))
477                 tprintf("%#lx", addr);
478         else if (tprint_timex(tcp, addr) < 0)
479                 tprints("{...}");
480         if (syserror(tcp))
481                 return 0;
482         tcp->auxstr = xlookup(adjtimex_state, tcp->u_rval);
483         if (tcp->auxstr)
484                 return RVAL_STR;
485         return 0;
486 }
487
488 SYS_FUNC(adjtimex)
489 {
490         if (exiting(tcp))
491                 return do_adjtimex(tcp, tcp->u_arg[0]);
492         return 0;
493 }
494
495 #include "xlat/clockflags.h"
496 #include "xlat/clocknames.h"
497
498 static void
499 printclockname(int clockid)
500 {
501 #ifdef CLOCKID_TO_FD
502 # include "xlat/cpuclocknames.h"
503
504         if (clockid < 0) {
505                 if ((clockid & CLOCKFD_MASK) == CLOCKFD)
506                         tprintf("FD_TO_CLOCKID(%d)", CLOCKID_TO_FD(clockid));
507                 else {
508                         if(CPUCLOCK_PERTHREAD(clockid))
509                                 tprintf("MAKE_THREAD_CPUCLOCK(%d,", CPUCLOCK_PID(clockid));
510                         else
511                                 tprintf("MAKE_PROCESS_CPUCLOCK(%d,", CPUCLOCK_PID(clockid));
512                         printxval(cpuclocknames, clockid & CLOCKFD_MASK, "CPUCLOCK_???");
513                         tprints(")");
514                 }
515         }
516         else
517 #endif
518                 printxval(clocknames, clockid, "CLOCK_???");
519 }
520
521 SYS_FUNC(clock_settime)
522 {
523         if (entering(tcp)) {
524                 printclockname(tcp->u_arg[0]);
525                 tprints(", ");
526                 printtv(tcp, tcp->u_arg[1]);
527         }
528         return 0;
529 }
530
531 SYS_FUNC(clock_gettime)
532 {
533         if (entering(tcp)) {
534                 printclockname(tcp->u_arg[0]);
535                 tprints(", ");
536         } else {
537                 if (syserror(tcp))
538                         tprintf("%#lx", tcp->u_arg[1]);
539                 else
540                         printtv(tcp, tcp->u_arg[1]);
541         }
542         return 0;
543 }
544
545 SYS_FUNC(clock_nanosleep)
546 {
547         if (entering(tcp)) {
548                 printclockname(tcp->u_arg[0]);
549                 tprints(", ");
550                 printflags(clockflags, tcp->u_arg[1], "TIMER_???");
551                 tprints(", ");
552                 printtv(tcp, tcp->u_arg[2]);
553                 tprints(", ");
554         } else {
555                 if (syserror(tcp))
556                         tprintf("%#lx", tcp->u_arg[3]);
557                 else
558                         printtv(tcp, tcp->u_arg[3]);
559         }
560         return 0;
561 }
562
563 SYS_FUNC(clock_adjtime)
564 {
565         if (exiting(tcp))
566                 return do_adjtimex(tcp, tcp->u_arg[1]);
567         printclockname(tcp->u_arg[0]);
568         tprints(", ");
569         return 0;
570 }
571
572 #ifndef SIGEV_THREAD_ID
573 # define SIGEV_THREAD_ID 4
574 #endif
575 #include "xlat/sigev_value.h"
576
577 #if SUPPORTED_PERSONALITIES > 1
578 static void
579 printsigevent32(struct tcb *tcp, long arg)
580 {
581         struct {
582                 int     sigev_value;
583                 int     sigev_signo;
584                 int     sigev_notify;
585
586                 union {
587                         int     tid;
588                         struct {
589                                 int     function, attribute;
590                         } thread;
591                 } un;
592         } sev;
593
594         if (umove(tcp, arg, &sev) < 0)
595                 tprints("{...}");
596         else {
597                 tprintf("{%#x, ", sev.sigev_value);
598                 if (sev.sigev_notify == SIGEV_SIGNAL)
599                         tprintf("%s, ", signame(sev.sigev_signo));
600                 else
601                         tprintf("%u, ", sev.sigev_signo);
602                 printxval(sigev_value, sev.sigev_notify, "SIGEV_???");
603                 tprints(", ");
604                 if (sev.sigev_notify == SIGEV_THREAD_ID)
605                         tprintf("{%d}", sev.un.tid);
606                 else if (sev.sigev_notify == SIGEV_THREAD)
607                         tprintf("{%#x, %#x}",
608                                 sev.un.thread.function,
609                                 sev.un.thread.attribute);
610                 else
611                         tprints("{...}");
612                 tprints("}");
613         }
614 }
615 #endif
616
617 void
618 printsigevent(struct tcb *tcp, long arg)
619 {
620         struct sigevent sev;
621
622 #if SUPPORTED_PERSONALITIES > 1
623         if (current_wordsize == 4) {
624                 printsigevent32(tcp, arg);
625                 return;
626         }
627 #endif
628         if (umove(tcp, arg, &sev) < 0)
629                 tprints("{...}");
630         else {
631                 tprintf("{%p, ", sev.sigev_value.sival_ptr);
632                 if (sev.sigev_notify == SIGEV_SIGNAL)
633                         tprintf("%s, ", signame(sev.sigev_signo));
634                 else
635                         tprintf("%u, ", sev.sigev_signo);
636                 printxval(sigev_value, sev.sigev_notify, "SIGEV_???");
637                 tprints(", ");
638                 if (sev.sigev_notify == SIGEV_THREAD_ID)
639 #if defined(HAVE_STRUCT_SIGEVENT__SIGEV_UN__PAD)
640                         /* _pad[0] is the _tid field which might not be
641                            present in the userlevel definition of the
642                            struct.  */
643                         tprintf("{%d}", sev._sigev_un._pad[0]);
644 #elif defined(HAVE_STRUCT_SIGEVENT___PAD)
645                         tprintf("{%d}", sev.__pad[0]);
646 #else
647 # warning unfamiliar struct sigevent => incomplete SIGEV_THREAD_ID decoding
648                         tprints("{...}");
649 #endif
650                 else if (sev.sigev_notify == SIGEV_THREAD)
651                         tprintf("{%p, %p}", sev.sigev_notify_function,
652                                 sev.sigev_notify_attributes);
653                 else
654                         tprints("{...}");
655                 tprints("}");
656         }
657 }
658
659 SYS_FUNC(timer_create)
660 {
661         if (entering(tcp)) {
662                 printclockname(tcp->u_arg[0]);
663                 tprints(", ");
664                 printsigevent(tcp, tcp->u_arg[1]);
665                 tprints(", ");
666         } else {
667                 int timer_id;
668
669                 if (syserror(tcp) || umove(tcp, tcp->u_arg[2], &timer_id) < 0)
670                         tprintf("%#lx", tcp->u_arg[2]);
671                 else
672                         tprintf("{%d}", timer_id);
673         }
674         return 0;
675 }
676
677 SYS_FUNC(timer_settime)
678 {
679         if (entering(tcp)) {
680                 tprintf("%#lx, ", tcp->u_arg[0]);
681                 printflags(clockflags, tcp->u_arg[1], "TIMER_???");
682                 tprints(", ");
683                 printitv(tcp, tcp->u_arg[2]);
684                 tprints(", ");
685         } else {
686                 if (syserror(tcp))
687                         tprintf("%#lx", tcp->u_arg[3]);
688                 else
689                         printitv(tcp, tcp->u_arg[3]);
690         }
691         return 0;
692 }
693
694 SYS_FUNC(timer_gettime)
695 {
696         if (entering(tcp)) {
697                 tprintf("%#lx, ", tcp->u_arg[0]);
698         } else {
699                 if (syserror(tcp))
700                         tprintf("%#lx", tcp->u_arg[1]);
701                 else
702                         printitv(tcp, tcp->u_arg[1]);
703         }
704         return 0;
705 }
706
707 static void
708 print_rtc(struct tcb *tcp, const struct rtc_time *rt)
709 {
710         tprintf("{tm_sec=%d, tm_min=%d, tm_hour=%d, "
711                 "tm_mday=%d, tm_mon=%d, tm_year=%d, ",
712                 rt->tm_sec, rt->tm_min, rt->tm_hour,
713                 rt->tm_mday, rt->tm_mon, rt->tm_year);
714         if (!abbrev(tcp))
715                 tprintf("tm_wday=%d, tm_yday=%d, tm_isdst=%d}",
716                         rt->tm_wday, rt->tm_yday, rt->tm_isdst);
717         else
718                 tprints("...}");
719 }
720
721 int
722 rtc_ioctl(struct tcb *tcp, const unsigned int code, long arg)
723 {
724         switch (code) {
725         case RTC_ALM_SET:
726         case RTC_SET_TIME:
727                 if (entering(tcp)) {
728                         struct rtc_time rt;
729                         if (umove(tcp, arg, &rt) < 0)
730                                 tprintf(", %#lx", arg);
731                         else {
732                                 tprints(", ");
733                                 print_rtc(tcp, &rt);
734                         }
735                 }
736                 break;
737         case RTC_ALM_READ:
738         case RTC_RD_TIME:
739                 if (exiting(tcp)) {
740                         struct rtc_time rt;
741                         if (syserror(tcp) || umove(tcp, arg, &rt) < 0)
742                                 tprintf(", %#lx", arg);
743                         else {
744                                 tprints(", ");
745                                 print_rtc(tcp, &rt);
746                         }
747                 }
748                 break;
749         case RTC_IRQP_SET:
750         case RTC_EPOCH_SET:
751                 if (entering(tcp))
752                         tprintf(", %lu", arg);
753                 break;
754         case RTC_IRQP_READ:
755         case RTC_EPOCH_READ:
756                 if (exiting(tcp))
757                         tprintf(", %lu", arg);
758                 break;
759         case RTC_WKALM_SET:
760                 if (entering(tcp)) {
761                         struct rtc_wkalrm wk;
762                         if (umove(tcp, arg, &wk) < 0)
763                                 tprintf(", %#lx", arg);
764                         else {
765                                 tprintf(", {enabled=%d, pending=%d, ",
766                                         wk.enabled, wk.pending);
767                                 print_rtc(tcp, &wk.time);
768                                 tprints("}");
769                         }
770                 }
771                 break;
772         case RTC_WKALM_RD:
773                 if (exiting(tcp)) {
774                         struct rtc_wkalrm wk;
775                         if (syserror(tcp) || umove(tcp, arg, &wk) < 0)
776                                 tprintf(", %#lx", arg);
777                         else {
778                                 tprintf(", {enabled=%d, pending=%d, ",
779                                         wk.enabled, wk.pending);
780                                 print_rtc(tcp, &wk.time);
781                                 tprints("}");
782                         }
783                 }
784                 break;
785         default:
786                 if (entering(tcp))
787                         tprintf(", %#lx", arg);
788                 break;
789         }
790         return 1;
791 }
792
793 #include "xlat/timerfdflags.h"
794
795 SYS_FUNC(timerfd)
796 {
797         if (entering(tcp)) {
798                 /* It does not matter that the kernel uses itimerspec.  */
799                 tprintf("%ld, ", tcp->u_arg[0]);
800                 printclockname(tcp->u_arg[0]);
801                 tprints(", ");
802                 printflags(timerfdflags, tcp->u_arg[2], "TFD_???");
803                 tprints(", ");
804                 printitv(tcp, tcp->u_arg[3]);
805         }
806         return 0;
807 }
808
809 SYS_FUNC(timerfd_create)
810 {
811         if (entering(tcp)) {
812                 printclockname(tcp->u_arg[0]);
813                 tprints(", ");
814                 printflags(timerfdflags, tcp->u_arg[1], "TFD_???");
815         }
816         return 0;
817 }
818
819 SYS_FUNC(timerfd_settime)
820 {
821         if (entering(tcp)) {
822                 printfd(tcp, tcp->u_arg[0]);
823                 tprints(", ");
824                 printflags(timerfdflags, tcp->u_arg[1], "TFD_???");
825                 tprints(", ");
826                 printitv(tcp, tcp->u_arg[2]);
827                 tprints(", ");
828                 printitv(tcp, tcp->u_arg[3]);
829         }
830         return 0;
831 }
832
833 SYS_FUNC(timerfd_gettime)
834 {
835         if (entering(tcp)) {
836                 printfd(tcp, tcp->u_arg[0]);
837                 tprints(", ");
838                 printitv(tcp, tcp->u_arg[1]);
839         }
840         return 0;
841 }