move everything out of trunk
[lttv.git] / tests / kernel / trace-event.h
1 #include <stdarg.h>
2
3 /* Maximum number of callbacks per marker */
4 #define LTT_NR_CALLBACKS 10
5
6 /* LTT flags
7 *
8 * LTT_FLAG_TRACE : first arg contains trace to write into.
9 * (type : struct ltt_trace_struct *)
10 * LTT_FLAG_CHANNEL : following arg contains channel index to write into.
11 * (type : uint8_t)
12 * LTT_FLAG_FORCE : Force write in disabled traces (internal ltt use)
13 */
14
15 #define _LTT_FLAG_TRACE 0
16 #define _LTT_FLAG_CHANNEL 1
17 #define _LTT_FLAG_FORCE 2
18
19 #define LTT_FLAG_TRACE (1 << _LTT_FLAG_TRACE)
20 #define LTT_FLAG_CHANNEL (1 << _LTT_FLAG_CHANNEL)
21 #define LTT_FLAG_FORCE (1 << _LTT_FLAG_FORCE)
22
23
24 char *(*ltt_serialize_cb)(char *buffer, int *cb_args,
25 const char *fmt, va_list args);
26
27
28 static int skip_atoi(const char **s)
29 {
30 int i=0;
31
32 while (isdigit(**s))
33 i = i*10 + *((*s)++) - '0';
34 return i;
35 }
36
37 /* Inspired from vsnprintf */
38 /* New types :
39 * %r : serialized fixed length struct, union, array.
40 * %v : serialized sequence
41 * %k : callback
42 */
43 static inline __attribute__((no_instrument_function))
44 char *ltt_serialize_data(char *buffer, int *cb_args,
45 const char *fmt, va_list args)
46 {
47 int len;
48 const char *s;
49 int elem_size; /* Size of the integer for 'b' */
50 /* Size of the data contained by 'r' */
51 int elem_alignment; /* Element alignment for 'r' */
52 int qualifier; /* 'h', 'l', or 'L' for integer fields */
53 /* 'z' support added 23/7/1999 S.H. */
54 /* 'z' changed to 'Z' --davidm 1/25/99 */
55 /* 't' added for ptrdiff_t */
56 char *str; /* Pointer to write to */
57 ltt_serialize_cb cb;
58 int cb_arg_nr = 0;
59
60 str = buf;
61
62 for (; *fmt ; ++fmt) {
63 if (*fmt != '%') {
64 /* Skip text */
65 continue;
66 }
67
68 /* process flags : ignore standard print formats for now. */
69 repeat:
70 ++fmt; /* this also skips first '%' */
71 switch (*fmt) {
72 case '-':
73 case '+':
74 case ' ':
75 case '#':
76 case '0': goto repeat;
77 }
78
79 /* get element size */
80 elem_size = -1;
81 if (isdigit(*fmt))
82 elem_size = skip_atoi(&fmt);
83 else if (*fmt == '*') {
84 ++fmt;
85 /* it's the next argument */
86 elem_size = va_arg(args, int);
87 }
88
89 /* get the alignment */
90 elem_alignment = -1;
91 if (*fmt == '.') {
92 ++fmt;
93 if (isdigit(*fmt))
94 elem_alignment = skip_atoi(&fmt);
95 else if (*fmt == '*') {
96 ++fmt;
97 /* it's the next argument */
98 elem_alignment = va_arg(args, int);
99 }
100 }
101
102 /* get the conversion qualifier */
103 qualifier = -1;
104 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
105 *fmt =='Z' || *fmt == 'z' || *fmt == 't') {
106 qualifier = *fmt;
107 ++fmt;
108 if (qualifier == 'l' && *fmt == 'l') {
109 qualifier = 'L';
110 ++fmt;
111 }
112 }
113
114 switch (*fmt) {
115 case 'c':
116 if (buffer)
117 *str = (char) va_arg(args, int);
118 str += sizeof(char);
119 continue;
120
121 case 's':
122 s = va_arg(args, char *);
123 if ((unsigned long)s < PAGE_SIZE)
124 s = "<NULL>";
125 if (buffer)
126 strcpy(str, s);
127 str += strlen(s);
128 /* Following alignment for genevent
129 * compatibility */
130 str += ltt_align(str, sizeof(void*));
131 continue;
132
133 case 'p':
134 str += ltt_align(str, sizeof(void*));
135 if (buffer)
136 *(void**)str = va_arg(args, void *);
137 continue;
138
139 case 'r':
140 /* For array, struct, union */
141 if (elem_alignment < 0)
142 elem_alignment = sizeof(void*);
143 str += ltt_align(str, elem_alignment);
144 if (elem_size > 0) {
145 const char *src = va_arg(args,
146 const char *);
147 if (buffer)
148 memcpy(str, src, elem_size);
149 str += elem_size;
150 }
151 continue;
152
153 case 'v':
154 /* For sequence */
155 str += ltt_align(str, sizeof(int));
156 if (buffer)
157 *(int*)str = elem_size;
158 str += sizeof(int);
159 if (elem_alignment > 0)
160 str += ltt_align(str, elem_alignment);
161 if (elem_size > 0) {
162 const char *src = va_arg(args,
163 const char *);
164 if (buffer)
165 memcpy(str, src, elem_size);
166 str += elem_size;
167 }
168 /* Following alignment for genevent
169 * compatibility */
170 str += ltt_align(str, sizeof(void*));
171 continue;
172
173 case 'k':
174 /* For callback */
175 cb = va_arg(args, ltt_serialize_cb);
176 /* The callback will take as many arguments
177 * as it needs from args. They won't be
178 * type verified. */
179 if (cb_arg_nr < LTT_NR_CALLBACKS)
180 str = cb(str, &cb_args[cb_arg_nr++],
181 fmt, args);
182 continue;
183
184 case 'n':
185 /* FIXME:
186 * What does C99 say about the overflow case
187 * here? */
188 if (qualifier == 'l') {
189 long * ip = va_arg(args, long *);
190 *ip = (str - buf);
191 } else if (qualifier == 'Z'
192 || qualifier == 'z') {
193 size_t * ip = va_arg(args, size_t *);
194 *ip = (str - buf);
195 } else {
196 int * ip = va_arg(args, int *);
197 *ip = (str - buf);
198 }
199 continue;
200
201 case '%':
202 continue;
203
204 case 'o':
205 case 'X':
206 case 'x':
207 case 'd':
208 case 'i':
209 case 'u':
210 break;
211
212 default:
213 if (!*fmt)
214 --fmt;
215 continue;
216 }
217 switch (qualifier) {
218 case 'L':
219 str += ltt_align(str, sizeof(long long));
220 if (buffer)
221 *(long long*)str = va_arg(args, long long);
222 str += sizeof(long long);
223 break;
224 case 'l':
225 str += ltt_align(str, sizeof(long));
226 if (buffer)
227 *(long*)str = va_arg(args, long);
228 str += sizeof(long);
229 break;
230 case 'Z':
231 case 'z':
232 str += ltt_align(str, sizeof(size_t));
233 if (buffer)
234 *(size_t*)str = va_arg(args, size_t);
235 str += sizeof(size_t);
236 break;
237 case 't':
238 str += ltt_align(str, sizeof(ptrdiff_t));
239 if (buffer)
240 *(ptrdiff_t*)str = va_arg(args, ptrdiff_t);
241 str += sizeof(ptrdiff_t);
242 break;
243 case 'h':
244 str += ltt_align(str, sizeof(short));
245 if (buffer)
246 *(short*)str = (short) va_arg(args, int);
247 str += sizeof(short);
248 break;
249 case 'b':
250 if (elem_size > 0)
251 str += ltt_align(str, elem_size);
252 if (buffer)
253 switch (elem_size) {
254 case 1:
255 *(int8_t*)str =
256 (int8_t)va_arg(args, int);
257 break;
258 case 2:
259 *(int16_t*)str =
260 (int16_t)va_arg(args, int);
261 break;
262 case 4:
263 *(int32_t*)str = va_arg(args, int32_t);
264 break;
265 case 8:
266 *(int64_t*)str = va_arg(args, int64_t);
267 break;
268 }
269 str += elem_size;
270 default:
271 str += ltt_align(str, sizeof(int));
272 if (buffer)
273 *(int*)str = va_arg(args, int);
274 str += sizeof(int);
275 }
276 }
277 return str;
278 }
279
280 /* Calculate data size */
281 /* Assume that the padding for alignment starts at a
282 * sizeof(void *) address. */
283 static inline __attribute__((no_instrument_function))
284 size_t ltt_get_data_size(ltt_facility_t fID, uint8_t eID,
285 int *cb_args,
286 const char *fmt, va_list args)
287 {
288 return (size_t)ltt_serialize_data(NULL, fmt, args);
289 }
290
291 static inline __attribute__((no_instrument_function))
292 void ltt_write_event_data(char *buffer,
293 ltt_facility_t fID, uint8_t eID,
294 int *cb_args,
295 const char *fmt, va_list args)
296 {
297 ltt_serialize_data(buffer, fmt, args);
298 }
299
300
301 __attribute__((no_instrument_function))
302 void _vtrace(ltt_facility_t fID, uint8_t eID, long flags,
303 const char *fmt, va_list args)
304 {
305 size_t data_size, slot_size;
306 int channel_index;
307 struct ltt_channel_struct *channel;
308 struct ltt_trace_struct *trace, *dest_trace;
309 void *transport_data;
310 uint64_t tsc;
311 char *buffer;
312 va_list args_copy;
313 int cb_args[LTT_NR_CALLBACKS];
314
315 /* This test is useful for quickly exiting static tracing when no
316 * trace is active. */
317 if (likely(ltt_traces.num_active_traces == 0
318 && !(flags & LTT_FLAG_FORCE)))
319 return;
320
321 preempt_disable();
322 ltt_nesting[smp_processor_id()]++;
323
324 if (unlikely(flags & LTT_FLAG_TRACE))
325 dest_trace = va_arg(args, struct ltt_trace_struct *);
326 if (unlikely(flags & LTT_FLAG_CHANNEL))
327 channel_index = va_arg(args, int);
328 else
329 channel_index = ltt_get_channel_index(fID, eID);
330
331 va_copy(args_copy, args); /* Check : skip 2 st args if trace/ch */
332 data_size = ltt_get_data_size(fID, eID, cb_args, fmt, args_copy);
333 va_end(args_copy);
334
335 /* Iterate on each traces */
336 list_for_each_entry_rcu(trace, &ltt_traces.head, list) {
337 if (unlikely(!trace->active && !(flags & LTT_FLAG_FORCE)))
338 continue;
339 if (unlikely(flags & LTT_FLAG_TRACE && trace != dest_trace))
340 continue;
341 channel = ltt_get_channel_from_index(trace, channel_index);
342 /* reserve space : header and data */
343 buffer = ltt_reserve_slot(trace, channel, &transport_data,
344 data_size, &slot_size, &tsc);
345 if (unlikely(!buffer))
346 continue; /* buffer full */
347 /* Out-of-order write : header and data */
348 buffer = ltt_write_event_header(trace, channel, buffer,
349 fID, eID, data_size, tsc);
350 va_copy(args_copy, args);
351 ltt_write_event_data(buffer, fID, eID, cb_args, fmt, args_copy);
352 va_end(args_copy);
353 /* Out-of-order commit */
354 ltt_commit_slot(channel, &transport_data, buffer, slot_size);
355 }
356
357 ltt_nesting[smp_processor_id()]--;
358 preempt_enable();
359 }
360
361 __attribute__((no_instrument_function))
362 void _trace(ltt_facility_t fID, uint8_t eID, long flags, const char *fmt, ...)
363 {
364 va_list args;
365
366 va_start(args, fmt);
367 _vtrace(fID, eID, flags, fmt, args);
368 va_end(args);
369 }
370
This page took 0.042035 seconds and 4 git commands to generate.