]> granicus.if.org Git - strace/blob - time.c
time.c: move fallback definitions of SIGEV_* values to xlat/
[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 <signal.h>
33 #include <linux/version.h>
34 #include <sys/timex.h>
35
36 #ifndef UTIME_NOW
37 #define UTIME_NOW ((1l << 30) - 1l)
38 #endif
39 #ifndef UTIME_OMIT
40 #define UTIME_OMIT ((1l << 30) - 2l)
41 #endif
42
43 #if SUPPORTED_PERSONALITIES > 1
44 # if defined X86_64 || defined X32
45 #  define current_time_t_is_compat (current_personality == 1)
46 # else
47 #  define current_time_t_is_compat (current_wordsize == 4)
48 # endif
49 # define current_time_t_is_int32 current_time_t_is_compat
50 #else
51 # define current_time_t_is_compat 0
52 # define current_time_t_is_int32 (sizeof(time_t) == 4)
53 #endif
54
55 struct timeval32
56 {
57         u_int32_t tv_sec, tv_usec;
58 };
59
60 static void
61 tprint_timeval32(struct tcb *tcp, const struct timeval32 *tv)
62 {
63         tprintf("{%u, %u}", tv->tv_sec, tv->tv_usec);
64 }
65
66 static void
67 tprint_timeval(struct tcb *tcp, const struct timeval *tv)
68 {
69         tprintf("{%ju, %ju}", (uintmax_t) tv->tv_sec, (uintmax_t) tv->tv_usec);
70 }
71
72 void
73 printtv_bitness(struct tcb *tcp, long addr, enum bitness_t bitness, int special)
74 {
75         char buf[TIMEVAL_TEXT_BUFSIZE];
76         sprinttv(buf, tcp, addr, bitness, special);
77         tprints(buf);
78 }
79
80 static char *
81 do_sprinttv(char *buf, const uintmax_t sec, const uintmax_t usec,
82             const int special)
83 {
84         if (special) {
85                 switch (usec) {
86                         case UTIME_NOW:
87                                 return stpcpy(buf, "UTIME_NOW");
88                         case UTIME_OMIT:
89                                 return stpcpy(buf, "UTIME_OMIT");
90                 }
91         }
92         return buf + sprintf(buf, "{%ju, %ju}", sec, usec);
93 }
94
95 char *
96 sprinttv(char *buf, struct tcb *tcp, long addr, enum bitness_t bitness, int special)
97 {
98         if (addr == 0)
99                 return stpcpy(buf, "NULL");
100
101         if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)))
102                 return buf + sprintf(buf, "%#lx", addr);
103
104         if (bitness == BITNESS_32 || current_time_t_is_compat)
105         {
106                 struct timeval32 tv;
107
108                 if (umove(tcp, addr, &tv) >= 0)
109                         return do_sprinttv(buf, tv.tv_sec, tv.tv_usec, special);
110         } else {
111                 struct timeval tv;
112
113                 if (umove(tcp, addr, &tv) >= 0)
114                         return do_sprinttv(buf, tv.tv_sec, tv.tv_usec, special);
115         }
116
117         return buf + sprintf(buf, "%#lx", addr);
118 }
119
120 void
121 print_timespec(struct tcb *tcp, long addr)
122 {
123         char buf[TIMESPEC_TEXT_BUFSIZE];
124         sprint_timespec(buf, tcp, addr);
125         tprints(buf);
126 }
127
128 void
129 sprint_timespec(char *buf, struct tcb *tcp, long addr)
130 {
131         if (addr == 0)
132                 strcpy(buf, "NULL");
133         else if (!verbose(tcp))
134                 sprintf(buf, "%#lx", addr);
135         else {
136                 int rc;
137
138 #if SUPPORTED_PERSONALITIES > 1
139                 if (current_time_t_is_compat) {
140                         struct timeval32 tv;
141
142                         rc = umove(tcp, addr, &tv);
143                         if (rc >= 0)
144                                 sprintf(buf, "{%u, %u}",
145                                         tv.tv_sec, tv.tv_usec);
146                 } else
147 #endif
148                 {
149                         struct timespec ts;
150
151                         rc = umove(tcp, addr, &ts);
152                         if (rc >= 0)
153                                 sprintf(buf, "{%ju, %ju}",
154                                         (uintmax_t) ts.tv_sec,
155                                         (uintmax_t) ts.tv_nsec);
156                 }
157                 if (rc < 0)
158                         strcpy(buf, "{...}");
159         }
160 }
161
162 SYS_FUNC(time)
163 {
164         if (exiting(tcp)) {
165                 if (current_time_t_is_int32)
166                         printnum_int(tcp, tcp->u_arg[0], "%d");
167                 else
168                         printnum_int64(tcp, tcp->u_arg[0], "%" PRId64);
169         }
170         return 0;
171 }
172
173 SYS_FUNC(gettimeofday)
174 {
175         if (exiting(tcp)) {
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                 printtv_bitness(tcp, tcp->u_arg[0], BITNESS_32, 0);
188                 tprints(", ");
189                 printtv_bitness(tcp, tcp->u_arg[1], BITNESS_32, 0);
190         }
191         return 0;
192 }
193 #endif
194
195 SYS_FUNC(settimeofday)
196 {
197         printtv(tcp, tcp->u_arg[0]);
198         tprints(", ");
199         printtv(tcp, tcp->u_arg[1]);
200
201         return RVAL_DECODED;
202 }
203
204 #ifdef ALPHA
205 SYS_FUNC(osf_settimeofday)
206 {
207         printtv_bitness(tcp, tcp->u_arg[0], BITNESS_32, 0);
208         tprints(", ");
209         printtv_bitness(tcp, tcp->u_arg[1], BITNESS_32, 0);
210
211         return RVAL_DECODED;
212 }
213 #endif
214
215 SYS_FUNC(adjtime)
216 {
217         if (entering(tcp)) {
218                 printtv(tcp, tcp->u_arg[0]);
219                 tprints(", ");
220         } else {
221                 printtv(tcp, tcp->u_arg[1]);
222         }
223         return 0;
224 }
225
226 SYS_FUNC(nanosleep)
227 {
228         if (entering(tcp)) {
229                 print_timespec(tcp, tcp->u_arg[0]);
230                 tprints(", ");
231         } else {
232                 /* Second (returned) timespec is only significant
233                  * if syscall was interrupted. On success, we print
234                  * only its address, since kernel doesn't modify it,
235                  * and printing the value may show uninitialized data.
236                  */
237                 switch (tcp->u_error) {
238                 default:
239                         /* Not interrupted (slept entire interval) */
240                         printaddr(tcp->u_arg[1]);
241                         break;
242                 case ERESTARTSYS:
243                 case ERESTARTNOINTR:
244                 case ERESTARTNOHAND:
245                 case ERESTART_RESTARTBLOCK:
246                         /* Interrupted */
247                         print_timespec(tcp, tcp->u_arg[1]);
248                 }
249         }
250         return 0;
251 }
252
253 #include "xlat/itimer_which.h"
254
255 static void
256 printitv_bitness(struct tcb *tcp, long addr, enum bitness_t bitness)
257 {
258         if (bitness == BITNESS_32 || current_time_t_is_compat) {
259                 struct {
260                         struct timeval32 it_interval, it_value;
261                 } itv;
262
263                 if (!umove_or_printaddr(tcp, addr, &itv)) {
264                         tprints("{it_interval=");
265                         tprint_timeval32(tcp, &itv.it_interval);
266                         tprints(", it_value=");
267                         tprint_timeval32(tcp, &itv.it_value);
268                         tprints("}");
269                 }
270         } else {
271                 struct itimerval itv;
272
273                 if (!umove_or_printaddr(tcp, addr, &itv)) {
274                         tprints("{it_interval=");
275                         tprint_timeval(tcp, &itv.it_interval);
276                         tprints(", it_value=");
277                         tprint_timeval(tcp, &itv.it_value);
278                         tprints("}");
279                 }
280         }
281 }
282
283 #define printitv(tcp, addr)     \
284         printitv_bitness((tcp), (addr), BITNESS_CURRENT)
285
286 SYS_FUNC(getitimer)
287 {
288         if (entering(tcp)) {
289                 printxval(itimer_which, tcp->u_arg[0], "ITIMER_???");
290                 tprints(", ");
291         } else {
292                 printitv(tcp, tcp->u_arg[1]);
293         }
294         return 0;
295 }
296
297 #ifdef ALPHA
298 SYS_FUNC(osf_getitimer)
299 {
300         if (entering(tcp)) {
301                 printxval(itimer_which, tcp->u_arg[0], "ITIMER_???");
302                 tprints(", ");
303         } else {
304                 printitv_bitness(tcp, tcp->u_arg[1], BITNESS_32);
305         }
306         return 0;
307 }
308 #endif
309
310 SYS_FUNC(setitimer)
311 {
312         if (entering(tcp)) {
313                 printxval(itimer_which, tcp->u_arg[0], "ITIMER_???");
314                 tprints(", ");
315                 printitv(tcp, tcp->u_arg[1]);
316                 tprints(", ");
317         } else {
318                 printitv(tcp, tcp->u_arg[2]);
319         }
320         return 0;
321 }
322
323 #ifdef ALPHA
324 SYS_FUNC(osf_setitimer)
325 {
326         if (entering(tcp)) {
327                 printxval(itimer_which, tcp->u_arg[0], "ITIMER_???");
328                 tprints(", ");
329                 printitv_bitness(tcp, tcp->u_arg[1], BITNESS_32);
330                 tprints(", ");
331         } else {
332                 printitv_bitness(tcp, tcp->u_arg[2], BITNESS_32);
333         }
334         return 0;
335 }
336 #endif
337
338 #include "xlat/adjtimex_modes.h"
339 #include "xlat/adjtimex_status.h"
340 #include "xlat/adjtimex_state.h"
341
342 #if SUPPORTED_PERSONALITIES > 1
343 static int
344 tprint_timex32(struct tcb *tcp, long addr)
345 {
346         struct {
347                 unsigned int modes;
348                 int     offset;
349                 int     freq;
350                 int     maxerror;
351                 int     esterror;
352                 int     status;
353                 int     constant;
354                 int     precision;
355                 int     tolerance;
356                 struct timeval32 time;
357                 int     tick;
358                 int     ppsfreq;
359                 int     jitter;
360                 int     shift;
361                 int     stabil;
362                 int     jitcnt;
363                 int     calcnt;
364                 int     errcnt;
365                 int     stbcnt;
366         } tx;
367
368         if (umove_or_printaddr(tcp, addr, &tx))
369                 return -1;
370
371         tprints("{modes=");
372         printflags(adjtimex_modes, tx.modes, "ADJ_???");
373         tprintf(", offset=%d, freq=%d, maxerror=%d, ",
374                 tx.offset, tx.freq, tx.maxerror);
375         tprintf("esterror=%u, status=", tx.esterror);
376         printflags(adjtimex_status, tx.status, "STA_???");
377         tprintf(", constant=%d, precision=%u, ",
378                 tx.constant, tx.precision);
379         tprintf("tolerance=%d, time=", tx.tolerance);
380         tprint_timeval32(tcp, &tx.time);
381         tprintf(", tick=%d, ppsfreq=%d, jitter=%d",
382                 tx.tick, tx.ppsfreq, tx.jitter);
383         tprintf(", shift=%d, stabil=%d, jitcnt=%d",
384                 tx.shift, tx.stabil, tx.jitcnt);
385         tprintf(", calcnt=%d, errcnt=%d, stbcnt=%d",
386                 tx.calcnt, tx.errcnt, tx.stbcnt);
387         tprints("}");
388         return 0;
389 }
390 #endif /* SUPPORTED_PERSONALITIES > 1 */
391
392 static int
393 tprint_timex(struct tcb *tcp, long addr)
394 {
395         struct timex tx;
396
397 #if SUPPORTED_PERSONALITIES > 1
398         if (current_time_t_is_compat)
399                 return tprint_timex32(tcp, addr);
400 #endif
401         if (umove_or_printaddr(tcp, addr, &tx))
402                 return -1;
403
404         tprints("{modes=");
405         printflags(adjtimex_modes, tx.modes, "ADJ_???");
406         tprintf(", offset=%jd, freq=%jd, maxerror=%ju, esterror=%ju, status=",
407                 (intmax_t) tx.offset, (intmax_t) tx.freq,
408                 (uintmax_t) tx.maxerror, (uintmax_t) tx.esterror);
409         printflags(adjtimex_status, tx.status, "STA_???");
410         tprintf(", constant=%jd, precision=%ju, tolerance=%jd, time=",
411                 (intmax_t) tx.constant, (uintmax_t) tx.precision,
412                 (intmax_t) tx.tolerance);
413         tprint_timeval(tcp, &tx.time);
414         tprintf(", tick=%jd, ppsfreq=%jd, jitter=%jd",
415                 (intmax_t) tx.tick, (intmax_t) tx.ppsfreq, (intmax_t) tx.jitter);
416         tprintf(", shift=%d, stabil=%jd, jitcnt=%jd",
417                 tx.shift, (intmax_t) tx.stabil, (intmax_t) tx.jitcnt);
418         tprintf(", calcnt=%jd, errcnt=%jd, stbcnt=%jd",
419                 (intmax_t) tx.calcnt, (intmax_t) tx.errcnt, (intmax_t) tx.stbcnt);
420         tprints("}");
421         return 0;
422 }
423
424 static int
425 do_adjtimex(struct tcb *tcp, long addr)
426 {
427         if (tprint_timex(tcp, addr))
428                 return 0;
429         tcp->auxstr = xlookup(adjtimex_state, tcp->u_rval);
430         if (tcp->auxstr)
431                 return RVAL_STR;
432         return 0;
433 }
434
435 SYS_FUNC(adjtimex)
436 {
437         if (exiting(tcp))
438                 return do_adjtimex(tcp, tcp->u_arg[0]);
439         return 0;
440 }
441
442 #include "xlat/clockflags.h"
443 #include "xlat/clocknames.h"
444
445 static void
446 printclockname(int clockid)
447 {
448 #ifdef CLOCKID_TO_FD
449 # include "xlat/cpuclocknames.h"
450
451         if (clockid < 0) {
452                 if ((clockid & CLOCKFD_MASK) == CLOCKFD)
453                         tprintf("FD_TO_CLOCKID(%d)", CLOCKID_TO_FD(clockid));
454                 else {
455                         if(CPUCLOCK_PERTHREAD(clockid))
456                                 tprintf("MAKE_THREAD_CPUCLOCK(%d,", CPUCLOCK_PID(clockid));
457                         else
458                                 tprintf("MAKE_PROCESS_CPUCLOCK(%d,", CPUCLOCK_PID(clockid));
459                         printxval(cpuclocknames, clockid & CLOCKFD_MASK, "CPUCLOCK_???");
460                         tprints(")");
461                 }
462         }
463         else
464 #endif
465                 printxval(clocknames, clockid, "CLOCK_???");
466 }
467
468 SYS_FUNC(clock_settime)
469 {
470         printclockname(tcp->u_arg[0]);
471         tprints(", ");
472         printtv(tcp, tcp->u_arg[1]);
473
474         return RVAL_DECODED;
475 }
476
477 SYS_FUNC(clock_gettime)
478 {
479         if (entering(tcp)) {
480                 printclockname(tcp->u_arg[0]);
481                 tprints(", ");
482         } else {
483                 printtv(tcp, tcp->u_arg[1]);
484         }
485         return 0;
486 }
487
488 SYS_FUNC(clock_nanosleep)
489 {
490         if (entering(tcp)) {
491                 printclockname(tcp->u_arg[0]);
492                 tprints(", ");
493                 printflags(clockflags, tcp->u_arg[1], "TIMER_???");
494                 tprints(", ");
495                 printtv(tcp, tcp->u_arg[2]);
496                 tprints(", ");
497         } else {
498                 printtv(tcp, tcp->u_arg[3]);
499         }
500         return 0;
501 }
502
503 SYS_FUNC(clock_adjtime)
504 {
505         if (exiting(tcp))
506                 return do_adjtimex(tcp, tcp->u_arg[1]);
507         printclockname(tcp->u_arg[0]);
508         tprints(", ");
509         return 0;
510 }
511
512 #include "xlat/sigev_value.h"
513
514 #if SUPPORTED_PERSONALITIES > 1
515 static void
516 printsigevent32(struct tcb *tcp, long arg)
517 {
518         struct {
519                 int     sigev_value;
520                 int     sigev_signo;
521                 int     sigev_notify;
522
523                 union {
524                         int     tid;
525                         struct {
526                                 int     function, attribute;
527                         } thread;
528                 } un;
529         } sev;
530
531         if (!umove_or_printaddr(tcp, arg, &sev)) {
532                 tprintf("{%#x, ", sev.sigev_value);
533                 if (sev.sigev_notify == SIGEV_SIGNAL)
534                         tprintf("%s, ", signame(sev.sigev_signo));
535                 else
536                         tprintf("%u, ", sev.sigev_signo);
537                 printxval(sigev_value, sev.sigev_notify, "SIGEV_???");
538                 tprints(", ");
539                 if (sev.sigev_notify == SIGEV_THREAD_ID)
540                         tprintf("{%d}", sev.un.tid);
541                 else if (sev.sigev_notify == SIGEV_THREAD)
542                         tprintf("{%#x, %#x}",
543                                 sev.un.thread.function,
544                                 sev.un.thread.attribute);
545                 else
546                         tprints("{...}");
547                 tprints("}");
548         }
549 }
550 #endif
551
552 void
553 printsigevent(struct tcb *tcp, long arg)
554 {
555         struct sigevent sev;
556
557 #if SUPPORTED_PERSONALITIES > 1
558         if (current_wordsize == 4) {
559                 printsigevent32(tcp, arg);
560                 return;
561         }
562 #endif
563         if (!umove_or_printaddr(tcp, arg, &sev)) {
564                 tprintf("{%p, ", sev.sigev_value.sival_ptr);
565                 if (sev.sigev_notify == SIGEV_SIGNAL)
566                         tprintf("%s, ", signame(sev.sigev_signo));
567                 else
568                         tprintf("%u, ", sev.sigev_signo);
569                 printxval(sigev_value, sev.sigev_notify, "SIGEV_???");
570                 tprints(", ");
571                 if (sev.sigev_notify == SIGEV_THREAD_ID)
572 #if defined(HAVE_STRUCT_SIGEVENT__SIGEV_UN__PAD)
573                         /* _pad[0] is the _tid field which might not be
574                            present in the userlevel definition of the
575                            struct.  */
576                         tprintf("{%d}", sev._sigev_un._pad[0]);
577 #elif defined(HAVE_STRUCT_SIGEVENT___PAD)
578                         tprintf("{%d}", sev.__pad[0]);
579 #else
580 # warning unfamiliar struct sigevent => incomplete SIGEV_THREAD_ID decoding
581                         tprints("{...}");
582 #endif
583                 else if (sev.sigev_notify == SIGEV_THREAD)
584                         tprintf("{%p, %p}", sev.sigev_notify_function,
585                                 sev.sigev_notify_attributes);
586                 else
587                         tprints("{...}");
588                 tprints("}");
589         }
590 }
591
592 SYS_FUNC(timer_create)
593 {
594         if (entering(tcp)) {
595                 printclockname(tcp->u_arg[0]);
596                 tprints(", ");
597                 printsigevent(tcp, tcp->u_arg[1]);
598                 tprints(", ");
599         } else {
600                 printnum_int(tcp, tcp->u_arg[2], "%d");
601         }
602         return 0;
603 }
604
605 SYS_FUNC(timer_settime)
606 {
607         if (entering(tcp)) {
608                 tprintf("%d, ", (int) tcp->u_arg[0]);
609                 printflags(clockflags, tcp->u_arg[1], "TIMER_???");
610                 tprints(", ");
611                 printitv(tcp, tcp->u_arg[2]);
612                 tprints(", ");
613         } else {
614                 printitv(tcp, tcp->u_arg[3]);
615         }
616         return 0;
617 }
618
619 SYS_FUNC(timer_gettime)
620 {
621         if (entering(tcp)) {
622                 tprintf("%d, ", (int) tcp->u_arg[0]);
623         } else {
624                 printitv(tcp, tcp->u_arg[1]);
625         }
626         return 0;
627 }
628
629 #include "xlat/timerfdflags.h"
630
631 SYS_FUNC(timerfd)
632 {
633         /* It does not matter that the kernel uses itimerspec.  */
634         tprintf("%ld, ", tcp->u_arg[0]);
635         printclockname(tcp->u_arg[0]);
636         tprints(", ");
637         printflags(timerfdflags, tcp->u_arg[2], "TFD_???");
638         tprints(", ");
639         printitv(tcp, tcp->u_arg[3]);
640
641         return RVAL_DECODED | RVAL_FD;
642 }
643
644 SYS_FUNC(timerfd_create)
645 {
646         printclockname(tcp->u_arg[0]);
647         tprints(", ");
648         printflags(timerfdflags, tcp->u_arg[1], "TFD_???");
649
650         return RVAL_DECODED | RVAL_FD;
651 }
652
653 SYS_FUNC(timerfd_settime)
654 {
655         printfd(tcp, tcp->u_arg[0]);
656         tprints(", ");
657         printflags(timerfdflags, tcp->u_arg[1], "TFD_???");
658         tprints(", ");
659         printitv(tcp, tcp->u_arg[2]);
660         tprints(", ");
661         printitv(tcp, tcp->u_arg[3]);
662
663         return RVAL_DECODED;
664 }
665
666 SYS_FUNC(timerfd_gettime)
667 {
668         if (entering(tcp)) {
669                 printfd(tcp, tcp->u_arg[0]);
670                 tprints(", ");
671         } else {
672                 printitv(tcp, tcp->u_arg[1]);
673         }
674         return 0;
675 }