1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2007 Mathieu Desnoyers
4 * Complete rewrite from the original version made by XangXiu Yang.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License Version 2.1 as published by the Free Software Foundation.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
29 #include <ltt/compiler.h>
30 #include <ltt/marker.h>
31 #include <ltt/ltt-private.h>
33 #define DEFAULT_MARKERS_NUM 100
34 #define DEFAULT_FIELDS_NUM 1
35 #define MAX_NAME_LEN 1024
37 static inline const char *parse_trace_type(struct marker_info
*info
,
39 char *trace_size
, enum ltt_type
*trace_type
,
40 unsigned long *attributes
)
42 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
43 /* 'z' support added 23/7/1999 S.H. */
44 /* 'z' changed to 'Z' --davidm 1/25/99 */
45 /* 't' added for ptrdiff_t */
47 /* parse attributes. */
51 *attributes
|= LTT_ATTRIBUTE_COMPACT
;
55 *attributes
|= LTT_ATTRIBUTE_NETWORK_BYTE_ORDER
;
60 /* get the conversion qualifier */
62 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' ||
63 *fmt
=='Z' || *fmt
== 'z' || *fmt
== 't' ||
64 *fmt
== 'S' || *fmt
== '1' || *fmt
== '2' ||
65 *fmt
== '4' || *fmt
== 8) {
68 if (qualifier
== 'l' && *fmt
== 'l') {
76 *trace_type
= LTT_TYPE_UNSIGNED_INT
;
77 *trace_size
= sizeof(char);
80 *trace_type
= LTT_TYPE_STRING
;
83 *trace_type
= LTT_TYPE_POINTER
;
84 *trace_size
= info
->pointer_size
;
88 *trace_type
= LTT_TYPE_SIGNED_INT
;
94 *trace_type
= LTT_TYPE_UNSIGNED_INT
;
103 *trace_size
= sizeof(long long);
106 *trace_size
= info
->long_size
;
110 *trace_size
= info
->size_t_size
;
113 *trace_size
= info
->pointer_size
;
116 *trace_size
= sizeof(short);
119 *trace_size
= sizeof(uint8_t);
122 *trace_size
= sizeof(guint16
);
125 *trace_size
= sizeof(uint32_t);
128 *trace_size
= sizeof(uint64_t);
131 *trace_size
= info
->int_size
;
140 * Field width and precision are *not* supported.
143 __attribute__((no_instrument_function
))
144 static inline const char *parse_c_type(struct marker_info
*info
,
146 char *c_size
, enum ltt_type
*c_type
, GString
*field_fmt
)
148 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
149 /* 'z' support added 23/7/1999 S.H. */
150 /* 'z' changed to 'Z' --davidm 1/25/99 */
151 /* 't' added for ptrdiff_t */
153 /* process flags : ignore standard print formats for now. */
161 g_string_append_c(field_fmt
, *fmt
);
166 /* get the conversion qualifier */
168 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' ||
169 *fmt
=='Z' || *fmt
== 'z' || *fmt
== 't' ||
173 if (qualifier
== 'l' && *fmt
== 'l') {
175 g_string_append_c(field_fmt
, *fmt
);
182 *c_type
= LTT_TYPE_UNSIGNED_INT
;
183 *c_size
= sizeof(unsigned char);
184 g_string_append_c(field_fmt
, *fmt
);
187 *c_type
= LTT_TYPE_STRING
;
190 *c_type
= LTT_TYPE_POINTER
;
191 *c_size
= info
->pointer_size
;
195 *c_type
= LTT_TYPE_SIGNED_INT
;
196 g_string_append_c(field_fmt
, 'l');
197 g_string_append_c(field_fmt
, 'l');
198 g_string_append_c(field_fmt
, *fmt
);
204 g_string_append_c(field_fmt
, 'l');
205 g_string_append_c(field_fmt
, 'l');
206 g_string_append_c(field_fmt
, *fmt
);
207 *c_type
= LTT_TYPE_UNSIGNED_INT
;
216 *c_size
= sizeof(long long);
219 *c_size
= info
->long_size
;
223 *c_size
= info
->size_t_size
;
226 *c_size
= info
->pointer_size
;
229 *c_size
= sizeof(short);
232 *c_size
= info
->int_size
;
239 static inline long add_type(struct marker_info
*info
,
240 long offset
, const char *name
,
241 char trace_size
, enum ltt_type trace_type
,
242 char c_size
, enum ltt_type c_type
, unsigned long attributes
,
243 unsigned int field_count
, GString
*field_fmt
)
245 struct marker_field
*field
;
246 char tmpname
[MAX_NAME_LEN
];
248 info
->fields
= g_array_set_size(info
->fields
, info
->fields
->len
+1);
249 field
= &g_array_index(info
->fields
, struct marker_field
,
250 info
->fields
->len
-1);
252 field
->name
= g_quark_from_string(name
);
254 snprintf(tmpname
, MAX_NAME_LEN
-1, "field %u", field_count
);
255 field
->name
= g_quark_from_string(tmpname
);
257 field
->type
= trace_type
;
258 field
->fmt
= g_string_new(field_fmt
->str
);
260 switch (trace_type
) {
261 case LTT_TYPE_SIGNED_INT
:
262 case LTT_TYPE_UNSIGNED_INT
:
263 case LTT_TYPE_POINTER
:
264 field
->size
= trace_size
;
265 field
->alignment
= trace_size
;
266 field
->attributes
= attributes
;
269 field
->static_offset
= 0;
272 field
->offset
= offset
+ ltt_align(offset
, field
->alignment
,
274 field
->static_offset
= 1;
275 return field
->offset
+ trace_size
;
277 case LTT_TYPE_STRING
:
278 field
->offset
= offset
;
279 field
->size
= 0; /* Variable length, size is 0 */
280 field
->alignment
= 1;
282 field
->static_offset
= 0;
284 field
->static_offset
= 1;
287 g_error("Unexpected type"); //FIXME: compact type
292 long marker_update_fields_offsets(struct marker_info
*info
, const char *data
)
294 struct marker_field
*field
;
298 /* Find the last field with a static offset, then update from there. */
299 for (i
= info
->fields
->len
- 1; i
>= 0; i
--) {
300 field
= &g_array_index(info
->fields
, struct marker_field
, i
);
301 if (field
->static_offset
) {
302 offset
= field
->offset
;
307 for (; i
< info
->fields
->len
; i
++) {
308 field
= &g_array_index(info
->fields
, struct marker_field
, i
);
310 switch (field
->type
) {
311 case LTT_TYPE_SIGNED_INT
:
312 case LTT_TYPE_UNSIGNED_INT
:
313 case LTT_TYPE_POINTER
:
314 field
->offset
= offset
+ ltt_align(offset
, field
->alignment
,
316 offset
= field
->offset
+ field
->size
;
318 case LTT_TYPE_STRING
:
319 field
->offset
= offset
;
320 offset
= offset
+ strlen(&data
[offset
]) + 1;
321 // not aligning on pointer size, breaking genevent backward compatibility.
324 g_error("Unexpected type"); //FIXME: compact type
331 static void format_parse(const char *fmt
, struct marker_info
*info
)
333 char trace_size
= 0, c_size
= 0; /*
334 * 0 (unset), 1, 2, 4, 8 bytes.
336 enum ltt_type trace_type
= LTT_TYPE_NONE
, c_type
= LTT_TYPE_NONE
;
337 unsigned long attributes
= 0;
339 const char *name_begin
= NULL
, *name_end
= NULL
;
341 unsigned int field_count
= 1;
342 GString
*field_fmt
= g_string_new("");
345 for (; *fmt
; ++fmt
) {
349 ++fmt
; /* skip first '#' */
350 if (*fmt
== '#') { /* Escaped ## */
351 g_string_append_c(field_fmt
, *fmt
);
352 g_string_append_c(field_fmt
, *fmt
);
356 fmt
= parse_trace_type(info
, fmt
, &trace_size
, &trace_type
,
361 g_string_append_c(field_fmt
, *fmt
);
362 ++fmt
; /* skip first '%' */
363 if (*fmt
== '%') { /* Escaped %% */
364 g_string_append_c(field_fmt
, *fmt
);
367 fmt
= parse_c_type(info
, fmt
, &c_size
, &c_type
, field_fmt
);
369 * Output c types if no trace types has been
374 if (trace_type
== LTT_TYPE_NONE
)
376 if (c_type
== LTT_TYPE_STRING
)
377 trace_type
= LTT_TYPE_STRING
;
378 /* perform trace write */
379 offset
= add_type(info
, offset
, name
, trace_size
,
380 trace_type
, c_size
, c_type
, attributes
, field_count
++,
382 g_string_truncate(field_fmt
, 0);
383 trace_size
= c_size
= 0;
384 trace_type
= c_size
= LTT_TYPE_NONE
;
385 g_string_truncate(field_fmt
, 0);
394 g_string_truncate(field_fmt
, 0);
395 if (!name_end
&& name_begin
) {
399 name
= g_new(char, name_end
- name_begin
+ 1);
400 memcpy(name
, name_begin
, name_end
- name_begin
);
401 name
[name_end
- name_begin
] = '\0';
403 break; /* Skip white spaces */
405 g_string_append_c(field_fmt
, *fmt
);
415 g_string_free(field_fmt
, TRUE
);
418 int marker_parse_format(const char *format
, struct marker_info
*info
)
421 g_array_free(info
->fields
, TRUE
);
422 info
->fields
= g_array_sized_new(FALSE
, TRUE
,
423 sizeof(struct marker_field
), DEFAULT_FIELDS_NUM
);
424 format_parse(format
, info
);
428 int marker_format_event(LttTrace
*trace
, GQuark name
, const char *format
)
430 struct marker_info
*info
;
434 fquery
= marker_get_format_from_name(trace
, name
);
436 if (strcmp(fquery
, format
) != 0)
437 g_error("Marker format mismatch \"%s\" vs \"%s\" for marker %s. "
438 "Kernel issue.", fquery
, format
, g_quark_to_string(name
));
440 return 0; /* Already exists. Nothing to do. */
442 fcopy
= g_new(char, strlen(format
)+1);
443 strcpy(fcopy
, format
);
444 g_hash_table_insert(trace
->markers_format_hash
, (gpointer
)(gulong
)name
,
447 info
= marker_get_info_from_name(trace
, name
);
448 for (; info
!= NULL
; info
= info
->next
) {
449 info
->format
= fcopy
;
450 if (marker_parse_format(format
, info
))
451 g_error("Error parsing marker format \"%s\" for marker \"%s\"", format
,
452 g_quark_to_string(name
));
457 int marker_id_event(LttTrace
*trace
, GQuark name
, guint16 id
,
458 uint8_t int_size
, uint8_t long_size
, uint8_t pointer_size
,
459 uint8_t size_t_size
, uint8_t alignment
)
461 struct marker_info
*info
, *head
;
464 if (trace
->markers
->len
<= id
)
465 trace
->markers
= g_array_set_size(trace
->markers
,
466 max(trace
->markers
->len
* 2, id
+ 1));
467 info
= &g_array_index(trace
->markers
, struct marker_info
, id
);
469 info
->int_size
= int_size
;
470 info
->long_size
= long_size
;
471 info
->pointer_size
= pointer_size
;
472 info
->size_t_size
= size_t_size
;
473 info
->alignment
= alignment
;
476 info
->format
= marker_get_format_from_name(trace
, name
);
477 if (info
->format
&& marker_parse_format(info
->format
, info
))
478 g_error("Error parsing marker format \"%s\" for marker \"%s\"",
479 info
->format
, g_quark_to_string(name
));
480 head
= marker_get_info_from_name(trace
, name
);
482 g_hash_table_insert(trace
->markers_hash
, (gpointer
)(gulong
)name
,
483 (gpointer
)(gulong
)id
);
485 struct marker_info
*iter
;
486 for (iter
= head
; iter
!= NULL
; iter
= iter
->next
)
487 if (iter
->name
== name
)
490 g_hash_table_replace(trace
->markers_hash
, (gpointer
)(gulong
)name
,
491 (gpointer
)(gulong
)id
);
498 int allocate_marker_data(LttTrace
*trace
)
500 /* Init array to 0 */
501 trace
->markers
= g_array_sized_new(FALSE
, TRUE
,
502 sizeof(struct marker_info
), DEFAULT_MARKERS_NUM
);
505 trace
->markers_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
506 if (!trace
->markers_hash
)
508 trace
->markers_format_hash
= g_hash_table_new_full(g_direct_hash
,
509 g_direct_equal
, NULL
, g_free
);
510 if (!trace
->markers_hash
)
515 void destroy_marker_data(LttTrace
*trace
)
518 struct marker_info
*info
;
519 struct marker_field
*field
;
521 for (i
=0; i
<trace
->markers
->len
; i
++) {
522 info
= &g_array_index(trace
->markers
, struct marker_info
, i
);
524 for (j
= 0; j
< info
->fields
->len
; j
++) {
525 field
= &g_array_index(info
->fields
, struct marker_field
, j
);
526 g_string_free(field
->fmt
, TRUE
);
528 g_array_free(info
->fields
, TRUE
);
531 g_array_free(trace
->markers
, TRUE
);
532 g_hash_table_destroy(trace
->markers_hash
);
533 g_hash_table_destroy(trace
->markers_format_hash
);