1 /*
2 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
3 * Copyright (c) 2016-2023 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8
9 #include "xstring.h"
10
11 #ifndef TIMESPEC_NSEC
12 # define TIMESPEC_NSEC tv_nsec
13 #endif
14
15 #ifndef UTIME_NOW
16 # define UTIME_NOW ((1l << 30) - 1l)
17 #endif
18 #ifndef UTIME_OMIT
19 # define UTIME_OMIT ((1l << 30) - 2l)
20 #endif
21
22 #define TIMESPEC_TO_SEC_NSEC(t_) \
23 ((long long) (t_)->tv_sec), \
24 zero_extend_signed_to_ull((t_)->TIMESPEC_NSEC)
25
26 static const char timespec_fmt[] =
27 "{tv_sec=%lld, " STRINGIFY_VAL(TIMESPEC_NSEC) "=%llu}";
28
29 static void
30 print_timespec_t(const TIMESPEC_T *t)
31 {
32 tprint_struct_begin();
33 PRINT_FIELD_D(*t, tv_sec);
34 tprint_struct_next();
35 tprints_field_name(STRINGIFY_VAL(TIMESPEC_NSEC));
36 PRINT_VAL_U(t->TIMESPEC_NSEC);
37 tprint_struct_end();
38 }
39
40 #if defined PRINT_TIMESPEC_DATA_SIZE || defined PRINT_TIMESPEC_ARRAY_DATA_SIZE
41 static void
42 print_unaligned_timespec_t(const void *arg)
43 {
44 TIMESPEC_T t;
45 memcpy(&t, arg, sizeof(t));
46 print_timespec_t(&t);
47 }
48 #endif /* PRINT_TIMESPEC_DATA_SIZE || PRINT_TIMESPEC_ARRAY_DATA_SIZE */
49
50 #ifdef PRINT_TIMESPEC_DATA_SIZE
51 bool
52 PRINT_TIMESPEC_DATA_SIZE(const void *arg, const size_t size)
53 {
54 if (size < sizeof(TIMESPEC_T)) {
55 tprint_unavailable();
56 return false;
57 }
58
59 print_unaligned_timespec_t(arg);
60 return true;
61 }
62 #endif /* PRINT_TIMESPEC_DATA_SIZE */
63
64 #ifdef PRINT_TIMESPEC_ARRAY_DATA_SIZE
65 bool
66 PRINT_TIMESPEC_ARRAY_DATA_SIZE(const void *arg, const unsigned int nmemb,
67 const size_t size)
68 {
69 if (nmemb > size / sizeof(TIMESPEC_T)) {
70 tprint_unavailable();
71 return false;
72 }
73
74 tprint_array_begin();
75
76 for (unsigned int i = 0; i < nmemb; i++, arg += sizeof(TIMESPEC_T)) {
77 if (i)
78 tprint_array_next();
79 print_unaligned_timespec_t(arg);
80 }
81
82 tprint_array_end();
83 return true;
84 }
85 #endif /* PRINT_TIMESPEC_ARRAY_DATA_SIZE */
86
87 #ifdef PRINT_TIMESPEC
88 int
89 PRINT_TIMESPEC(struct tcb *const tcp, const kernel_ulong_t addr)
90 {
91 TIMESPEC_T t;
92
93 if (umove_or_printaddr(tcp, addr, &t))
94 return -1;
95
96 print_timespec_t(&t);
97 return 0;
98 }
99 #endif /* PRINT_TIMESPEC */
100
101 #ifdef SPRINT_TIMESPEC
102 const char *
103 SPRINT_TIMESPEC(struct tcb *const tcp, const kernel_ulong_t addr)
104 {
105 TIMESPEC_T t;
106 static char buf[sizeof(timespec_fmt) + 3 * sizeof(t)];
107
108 if (!addr) {
109 strcpy(buf, "NULL");
110 } else if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)) ||
111 umove(tcp, addr, &t)) {
112 xsprintf(buf, "%#" PRI_klx, addr);
113 } else {
114 xsprintf(buf, timespec_fmt, TIMESPEC_TO_SEC_NSEC(&t));
115 }
116
117 return buf;
118 }
119 #endif /* SPRINT_TIMESPEC */
120
121 #ifdef PRINT_TIMESPEC_UTIME_PAIR
122 static bool
123 print_timespec_t_utime(struct tcb *tcp, void *elem_buf, size_t elem_size,
124 void *data)
125 {
126 const TIMESPEC_T *const t = elem_buf;
127 switch (t->TIMESPEC_NSEC) {
128 case UTIME_NOW:
129 case UTIME_OMIT:
130 if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV)
131 print_timespec_t(t);
132 if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
133 break;
134
135 (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE
136 ? tprints_comment : tprints_string)(t->TIMESPEC_NSEC == UTIME_NOW
137 ? "UTIME_NOW" : "UTIME_OMIT");
138 break;
139 default:
140 print_timespec_t(t);
141 tprints_comment(sprinttime_nsec(TIMESPEC_TO_SEC_NSEC(t)));
142 break;
143 }
144 return true;
145 }
146
147 int
148 PRINT_TIMESPEC_UTIME_PAIR(struct tcb *const tcp, const kernel_ulong_t addr)
149 {
150 TIMESPEC_T t[2];
151
152 if (umove_or_printaddr(tcp, addr, &t))
153 return -1;
154
155 print_local_array(tcp, t, print_timespec_t_utime);
156 return 0;
157 }
158 #endif /* PRINT_TIMESPEC_UTIME_PAIR */
159
160 #ifdef PRINT_ITIMERSPEC
161 int
162 PRINT_ITIMERSPEC(struct tcb *const tcp, const kernel_ulong_t addr)
163 {
164 struct { TIMESPEC_T it_interval, it_value; } t;
165
166 if (umove_or_printaddr(tcp, addr, &t))
167 return -1;
168
169 tprint_struct_begin();
170 PRINT_FIELD_OBJ_PTR(t, it_interval, print_timespec_t);
171 tprint_struct_next();
172 PRINT_FIELD_OBJ_PTR(t, it_value, print_timespec_t);
173 tprint_struct_end();
174 return 0;
175 }
176 #endif /* PRINT_ITIMERSPEC */