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') {
181 *c_type
= LTT_TYPE_UNSIGNED_INT
;
182 *c_size
= sizeof(unsigned char);
183 g_string_append_c(field_fmt
, *fmt
);
186 *c_type
= LTT_TYPE_STRING
;
189 *c_type
= LTT_TYPE_POINTER
;
190 *c_size
= info
->pointer_size
;
194 *c_type
= LTT_TYPE_SIGNED_INT
;
195 g_string_append_c(field_fmt
, 'l');
196 g_string_append_c(field_fmt
, 'l');
197 g_string_append_c(field_fmt
, *fmt
);
203 g_string_append_c(field_fmt
, 'l');
204 g_string_append_c(field_fmt
, 'l');
205 g_string_append_c(field_fmt
, *fmt
);
206 *c_type
= LTT_TYPE_UNSIGNED_INT
;
215 *c_size
= sizeof(long long);
218 *c_size
= info
->long_size
;
222 *c_size
= info
->size_t_size
;
225 *c_size
= info
->pointer_size
;
228 *c_size
= sizeof(short);
231 *c_size
= info
->int_size
;
238 static inline long add_type(struct marker_info
*info
,
239 long offset
, const char *name
,
240 char trace_size
, enum ltt_type trace_type
,
241 char c_size
, enum ltt_type c_type
, unsigned long attributes
,
242 unsigned int field_count
, GString
*field_fmt
)
244 struct marker_field
*field
;
245 char tmpname
[MAX_NAME_LEN
];
247 info
->fields
= g_array_set_size(info
->fields
, info
->fields
->len
+1);
248 field
= &g_array_index(info
->fields
, struct marker_field
,
249 info
->fields
->len
-1);
251 field
->name
= g_quark_from_string(name
);
253 snprintf(tmpname
, MAX_NAME_LEN
-1, "field %u", field_count
);
254 field
->name
= g_quark_from_string(tmpname
);
256 field
->type
= trace_type
;
257 field
->fmt
= g_string_new(field_fmt
->str
);
259 switch (trace_type
) {
260 case LTT_TYPE_SIGNED_INT
:
261 case LTT_TYPE_UNSIGNED_INT
:
262 case LTT_TYPE_POINTER
:
263 field
->size
= trace_size
;
264 field
->alignment
= trace_size
;
265 field
->attributes
= attributes
;
268 field
->static_offset
= 0;
271 field
->offset
= offset
+ ltt_align(offset
, field
->alignment
,
273 field
->static_offset
= 1;
274 return field
->offset
+ trace_size
;
276 case LTT_TYPE_STRING
:
277 field
->offset
= offset
;
278 field
->size
= 0; /* Variable length, size is 0 */
279 field
->alignment
= 1;
281 field
->static_offset
= 0;
283 field
->static_offset
= 1;
286 g_error("Unexpected type"); //FIXME: compact type
291 long marker_update_fields_offsets(struct marker_info
*info
, const char *data
)
293 struct marker_field
*field
;
297 /* Find the last field with a static offset, then update from there. */
298 for (i
= info
->fields
->len
- 1; i
>= 0; i
--) {
299 field
= &g_array_index(info
->fields
, struct marker_field
, i
);
300 if (field
->static_offset
) {
301 offset
= field
->offset
;
306 for (; i
< info
->fields
->len
; i
++) {
307 field
= &g_array_index(info
->fields
, struct marker_field
, i
);
309 switch (field
->type
) {
310 case LTT_TYPE_SIGNED_INT
:
311 case LTT_TYPE_UNSIGNED_INT
:
312 case LTT_TYPE_POINTER
:
313 field
->offset
= offset
+ ltt_align(offset
, field
->alignment
,
315 offset
= field
->offset
+ field
->size
;
317 case LTT_TYPE_STRING
:
318 field
->offset
= offset
;
319 offset
= offset
+ strlen(&data
[offset
]) + 1;
320 // not aligning on pointer size, breaking genevent backward compatibility.
323 g_error("Unexpected type"); //FIXME: compact type
330 static void format_parse(const char *fmt
, struct marker_info
*info
)
332 char trace_size
= 0, c_size
= 0; /*
333 * 0 (unset), 1, 2, 4, 8 bytes.
335 enum ltt_type trace_type
= LTT_TYPE_NONE
, c_type
= LTT_TYPE_NONE
;
336 unsigned long attributes
= 0;
338 const char *name_begin
= NULL
, *name_end
= NULL
;
340 unsigned int field_count
= 1;
341 GString
*field_fmt
= g_string_new("");
344 for (; *fmt
; ++fmt
) {
348 ++fmt
; /* skip first '#' */
349 if (*fmt
== '#') { /* Escaped ## */
350 g_string_append_c(field_fmt
, *fmt
);
351 g_string_append_c(field_fmt
, *fmt
);
355 fmt
= parse_trace_type(info
, fmt
, &trace_size
, &trace_type
,
360 g_string_append_c(field_fmt
, *fmt
);
361 ++fmt
; /* skip first '%' */
362 if (*fmt
== '%') { /* Escaped %% */
363 g_string_append_c(field_fmt
, *fmt
);
366 fmt
= parse_c_type(info
, fmt
, &c_size
, &c_type
, field_fmt
);
368 * Output c types if no trace types has been
373 if (trace_type
== LTT_TYPE_NONE
)
375 if (c_type
== LTT_TYPE_STRING
)
376 trace_type
= LTT_TYPE_STRING
;
377 /* perform trace write */
378 offset
= add_type(info
, offset
, name
, trace_size
,
379 trace_type
, c_size
, c_type
, attributes
, field_count
++,
381 trace_size
= c_size
= 0;
382 trace_type
= c_size
= LTT_TYPE_NONE
;
383 g_string_truncate(field_fmt
, 0);
392 g_string_truncate(field_fmt
, 0);
393 if (!name_end
&& name_begin
) {
397 name
= g_new(char, name_end
- name_begin
+ 1);
398 memcpy(name
, name_begin
, name_end
- name_begin
);
399 name
[name_end
- name_begin
] = '\0';
401 break; /* Skip white spaces */
403 g_string_append_c(field_fmt
, *fmt
);
413 g_string_free(field_fmt
, TRUE
);
416 int marker_parse_format(const char *format
, struct marker_info
*info
)
419 g_array_free(info
->fields
, TRUE
);
420 info
->fields
= g_array_sized_new(FALSE
, TRUE
,
421 sizeof(struct marker_field
), DEFAULT_FIELDS_NUM
);
422 format_parse(format
, info
);
426 int marker_format_event(LttTrace
*trace
, GQuark name
, const char *format
)
428 struct marker_info
*info
;
432 fquery
= marker_get_format_from_name(trace
, name
);
434 if (strcmp(fquery
, format
) != 0)
435 g_error("Marker format mismatch \"%s\" vs \"%s\" for marker %s. "
436 "Kernel issue.", fquery
, format
, g_quark_to_string(name
));
438 return 0; /* Already exists. Nothing to do. */
440 fcopy
= g_new(char, strlen(format
)+1);
441 strcpy(fcopy
, format
);
442 g_hash_table_insert(trace
->markers_format_hash
, (gpointer
)(gulong
)name
,
445 info
= marker_get_info_from_name(trace
, name
);
446 for (; info
!= NULL
; info
= info
->next
) {
447 info
->format
= fcopy
;
448 if (marker_parse_format(format
, info
))
449 g_error("Error parsing marker format \"%s\" for marker \"%s\"", format
,
450 g_quark_to_string(name
));
455 int marker_id_event(LttTrace
*trace
, GQuark name
, guint16 id
,
456 uint8_t int_size
, uint8_t long_size
, uint8_t pointer_size
,
457 uint8_t size_t_size
, uint8_t alignment
)
459 struct marker_info
*info
, *head
;
462 if (trace
->markers
->len
<= id
)
463 trace
->markers
= g_array_set_size(trace
->markers
,
464 max(trace
->markers
->len
* 2, id
+ 1));
465 info
= &g_array_index(trace
->markers
, struct marker_info
, id
);
467 info
->int_size
= int_size
;
468 info
->long_size
= long_size
;
469 info
->pointer_size
= pointer_size
;
470 info
->size_t_size
= size_t_size
;
471 info
->alignment
= alignment
;
474 info
->format
= marker_get_format_from_name(trace
, name
);
475 if (info
->format
&& marker_parse_format(info
->format
, info
))
476 g_error("Error parsing marker format \"%s\" for marker \"%s\"",
477 info
->format
, g_quark_to_string(name
));
478 head
= marker_get_info_from_name(trace
, name
);
480 g_hash_table_insert(trace
->markers_hash
, (gpointer
)(gulong
)name
,
481 (gpointer
)(gulong
)id
);
483 struct marker_info
*iter
;
484 for (iter
= head
; iter
!= NULL
; iter
= iter
->next
)
485 if (iter
->name
== name
)
488 g_hash_table_replace(trace
->markers_hash
, (gpointer
)(gulong
)name
,
489 (gpointer
)(gulong
)id
);
496 int allocate_marker_data(LttTrace
*trace
)
498 /* Init array to 0 */
499 trace
->markers
= g_array_sized_new(FALSE
, TRUE
,
500 sizeof(struct marker_info
), DEFAULT_MARKERS_NUM
);
503 trace
->markers_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
504 if (!trace
->markers_hash
)
506 trace
->markers_format_hash
= g_hash_table_new_full(g_direct_hash
,
507 g_direct_equal
, NULL
, g_free
);
508 if (!trace
->markers_hash
)
513 void destroy_marker_data(LttTrace
*trace
)
516 struct marker_info
*info
;
517 struct marker_field
*field
;
519 for (i
=0; i
<trace
->markers
->len
; i
++) {
520 info
= &g_array_index(trace
->markers
, struct marker_info
, i
);
522 for (j
= 0; j
< info
->fields
->len
; j
++) {
523 field
= &g_array_index(info
->fields
, struct marker_field
, j
);
524 g_string_free(field
->fmt
, TRUE
);
526 g_array_free(info
->fields
, TRUE
);
529 g_array_free(trace
->markers
, TRUE
);
530 g_hash_table_destroy(trace
->markers_hash
);
531 g_hash_table_destroy(trace
->markers_format_hash
);