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_NETWORK_BYTE_ORDER
;
56 /* get the conversion qualifier */
58 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' ||
59 *fmt
=='Z' || *fmt
== 'z' || *fmt
== 't' ||
60 *fmt
== 'S' || *fmt
== '1' || *fmt
== '2' ||
61 *fmt
== '4' || *fmt
== '8') {
64 if (qualifier
== 'l' && *fmt
== 'l') {
72 *trace_type
= LTT_TYPE_UNSIGNED_INT
;
73 *trace_size
= sizeof(char);
76 *trace_type
= LTT_TYPE_STRING
;
79 *trace_type
= LTT_TYPE_POINTER
;
80 *trace_size
= info
->pointer_size
;
84 *trace_type
= LTT_TYPE_SIGNED_INT
;
90 *trace_type
= LTT_TYPE_UNSIGNED_INT
;
99 *trace_size
= sizeof(long long);
102 *trace_size
= info
->long_size
;
106 *trace_size
= info
->size_t_size
;
109 *trace_size
= info
->pointer_size
;
112 *trace_size
= sizeof(short);
115 *trace_size
= sizeof(uint8_t);
118 *trace_size
= sizeof(guint16
);
121 *trace_size
= sizeof(uint32_t);
124 *trace_size
= sizeof(uint64_t);
127 *trace_size
= info
->int_size
;
136 * Field width and precision are *not* supported.
139 __attribute__((no_instrument_function
))
140 static inline const char *parse_c_type(struct marker_info
*info
,
142 char *c_size
, enum ltt_type
*c_type
, GString
*field_fmt
)
144 int qualifier
; /* 'h', 'l', or 'L' for integer fields */
145 /* 'z' support added 23/7/1999 S.H. */
146 /* 'z' changed to 'Z' --davidm 1/25/99 */
147 /* 't' added for ptrdiff_t */
149 /* process flags : ignore standard print formats for now. */
157 g_string_append_c(field_fmt
, *fmt
);
162 /* get the conversion qualifier */
164 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' ||
165 *fmt
=='Z' || *fmt
== 'z' || *fmt
== 't' ||
169 if (qualifier
== 'l' && *fmt
== 'l') {
177 *c_type
= LTT_TYPE_UNSIGNED_INT
;
178 *c_size
= sizeof(unsigned char);
179 g_string_append_c(field_fmt
, *fmt
);
182 *c_type
= LTT_TYPE_STRING
;
185 *c_type
= LTT_TYPE_POINTER
;
186 *c_size
= info
->pointer_size
;
190 *c_type
= LTT_TYPE_SIGNED_INT
;
191 g_string_append_c(field_fmt
, 'l');
192 g_string_append_c(field_fmt
, 'l');
193 g_string_append_c(field_fmt
, *fmt
);
199 g_string_append_c(field_fmt
, 'l');
200 g_string_append_c(field_fmt
, 'l');
201 g_string_append_c(field_fmt
, *fmt
);
202 *c_type
= LTT_TYPE_UNSIGNED_INT
;
211 *c_size
= sizeof(long long);
214 *c_size
= info
->long_size
;
218 *c_size
= info
->size_t_size
;
221 *c_size
= info
->pointer_size
;
224 *c_size
= sizeof(short);
227 *c_size
= info
->int_size
;
234 static inline long add_type(struct marker_info
*info
,
235 long offset
, const char *name
,
236 char trace_size
, enum ltt_type trace_type
,
237 char c_size
, enum ltt_type c_type
, unsigned long attributes
,
238 unsigned int field_count
, GString
*field_fmt
)
240 struct marker_field
*field
;
241 char tmpname
[MAX_NAME_LEN
];
243 info
->fields
= g_array_set_size(info
->fields
, info
->fields
->len
+1);
244 field
= &g_array_index(info
->fields
, struct marker_field
,
245 info
->fields
->len
-1);
247 field
->name
= g_quark_from_string(name
);
249 snprintf(tmpname
, MAX_NAME_LEN
-1, "field %u", field_count
);
250 field
->name
= g_quark_from_string(tmpname
);
252 field
->type
= trace_type
;
253 field
->fmt
= g_string_new(field_fmt
->str
);
255 switch (trace_type
) {
256 case LTT_TYPE_SIGNED_INT
:
257 case LTT_TYPE_UNSIGNED_INT
:
258 case LTT_TYPE_POINTER
:
259 field
->size
= trace_size
;
260 field
->alignment
= trace_size
;
261 info
->largest_align
= max((guint8
)field
->alignment
,
262 (guint8
)info
->largest_align
);
263 field
->attributes
= attributes
;
266 field
->static_offset
= 0;
269 field
->offset
= offset
+ ltt_align(offset
, field
->alignment
,
271 field
->static_offset
= 1;
272 return field
->offset
+ trace_size
;
274 case LTT_TYPE_STRING
:
275 field
->offset
= offset
;
276 field
->size
= 0; /* Variable length, size is 0 */
277 field
->alignment
= 1;
279 field
->static_offset
= 0;
281 field
->static_offset
= 1;
284 g_error("Unexpected type");
289 long marker_update_fields_offsets(struct marker_info
*info
, const char *data
)
291 struct marker_field
*field
;
295 /* Find the last field with a static offset, then update from there. */
296 for (i
= info
->fields
->len
- 1; i
>= 0; i
--) {
297 field
= &g_array_index(info
->fields
, struct marker_field
, i
);
298 if (field
->static_offset
) {
299 offset
= field
->offset
;
304 for (; i
< info
->fields
->len
; i
++) {
305 field
= &g_array_index(info
->fields
, struct marker_field
, i
);
307 switch (field
->type
) {
308 case LTT_TYPE_SIGNED_INT
:
309 case LTT_TYPE_UNSIGNED_INT
:
310 case LTT_TYPE_POINTER
:
311 field
->offset
= offset
+ ltt_align(offset
, field
->alignment
,
313 offset
= field
->offset
+ field
->size
;
315 case LTT_TYPE_STRING
:
316 field
->offset
= offset
;
317 offset
= offset
+ strlen(&data
[offset
]) + 1;
318 // not aligning on pointer size, breaking genevent backward compatibility.
321 g_error("Unexpected type");
328 static void format_parse(const char *fmt
, struct marker_info
*info
)
330 char trace_size
= 0, c_size
= 0; /*
331 * 0 (unset), 1, 2, 4, 8 bytes.
333 enum ltt_type trace_type
= LTT_TYPE_NONE
, c_type
= LTT_TYPE_NONE
;
334 unsigned long attributes
= 0;
336 const char *name_begin
= NULL
, *name_end
= NULL
;
338 unsigned int field_count
= 1;
339 GString
*field_fmt
= g_string_new("");
342 for (; *fmt
; ++fmt
) {
346 ++fmt
; /* skip first '#' */
347 if (*fmt
== '#') { /* Escaped ## */
348 g_string_append_c(field_fmt
, *fmt
);
349 g_string_append_c(field_fmt
, *fmt
);
353 fmt
= parse_trace_type(info
, fmt
, &trace_size
, &trace_type
,
358 g_string_append_c(field_fmt
, *fmt
);
359 ++fmt
; /* skip first '%' */
360 if (*fmt
== '%') { /* Escaped %% */
361 g_string_append_c(field_fmt
, *fmt
);
364 fmt
= parse_c_type(info
, fmt
, &c_size
, &c_type
, field_fmt
);
366 * Output c types if no trace types has been
371 if (trace_type
== LTT_TYPE_NONE
)
373 if (c_type
== LTT_TYPE_STRING
)
374 trace_type
= LTT_TYPE_STRING
;
375 /* perform trace write */
376 offset
= add_type(info
, offset
, name
, trace_size
,
377 trace_type
, c_size
, c_type
, attributes
, field_count
++,
379 trace_size
= c_size
= 0;
380 trace_type
= c_size
= LTT_TYPE_NONE
;
381 g_string_truncate(field_fmt
, 0);
390 g_string_truncate(field_fmt
, 0);
391 if (!name_end
&& name_begin
) {
395 name
= g_new(char, name_end
- name_begin
+ 1);
396 memcpy(name
, name_begin
, name_end
- name_begin
);
397 name
[name_end
- name_begin
] = '\0';
399 break; /* Skip white spaces */
401 g_string_append_c(field_fmt
, *fmt
);
411 g_string_free(field_fmt
, TRUE
);
414 int marker_parse_format(const char *format
, struct marker_info
*info
)
417 g_array_free(info
->fields
, TRUE
);
418 info
->fields
= g_array_sized_new(FALSE
, TRUE
,
419 sizeof(struct marker_field
), DEFAULT_FIELDS_NUM
);
420 format_parse(format
, info
);
424 int marker_format_event(LttTrace
*trace
, GQuark channel
, GQuark name
,
427 struct marker_info
*info
;
428 struct marker_data
*mdata
;
433 group
= g_datalist_id_get_data(&trace
->tracefiles
, channel
);
436 g_assert(group
->len
> 0);
437 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
439 fquery
= marker_get_format_from_name(mdata
, name
);
441 if (strcmp(fquery
, format
) != 0)
442 g_error("Marker format mismatch \"%s\" vs \"%s\" for marker %s.%s. "
443 "Kernel issue.", fquery
, format
,
444 g_quark_to_string(channel
), g_quark_to_string(name
));
446 return 0; /* Already exists. Nothing to do. */
448 fcopy
= g_new(char, strlen(format
)+1);
449 strcpy(fcopy
, format
);
450 g_hash_table_insert(mdata
->markers_format_hash
, (gpointer
)(gulong
)name
,
453 info
= marker_get_info_from_name(mdata
, name
);
454 for (; info
!= NULL
; info
= info
->next
) {
455 info
->format
= fcopy
;
456 if (marker_parse_format(format
, info
))
457 g_error("Error parsing marker format \"%s\" for marker \"%.s.%s\"",
458 format
, g_quark_to_string(channel
), g_quark_to_string(name
));
463 int marker_id_event(LttTrace
*trace
, GQuark channel
, GQuark name
, guint16 id
,
464 uint8_t int_size
, uint8_t long_size
, uint8_t pointer_size
,
465 uint8_t size_t_size
, uint8_t alignment
)
467 struct marker_data
*mdata
;
468 struct marker_info
*info
, *head
;
472 g_debug("Add channel %s event %s %hu\n", g_quark_to_string(channel
),
473 g_quark_to_string(name
), id
);
475 group
= g_datalist_id_get_data(&trace
->tracefiles
, channel
);
478 g_assert(group
->len
> 0);
479 mdata
= g_array_index (group
, LttTracefile
, 0).mdata
;
481 if (mdata
->markers
->len
<= id
)
482 mdata
->markers
= g_array_set_size(mdata
->markers
,
483 max(mdata
->markers
->len
* 2, id
+ 1));
484 info
= &g_array_index(mdata
->markers
, struct marker_info
, id
);
486 info
->int_size
= int_size
;
487 info
->long_size
= long_size
;
488 info
->pointer_size
= pointer_size
;
489 info
->size_t_size
= size_t_size
;
490 info
->alignment
= alignment
;
493 info
->format
= marker_get_format_from_name(mdata
, name
);
494 info
->largest_align
= 1;
495 if (info
->format
&& marker_parse_format(info
->format
, info
))
496 g_error("Error parsing marker format \"%s\" for marker \"%s.%s\"",
497 info
->format
, g_quark_to_string(channel
), g_quark_to_string(name
));
498 head
= marker_get_info_from_name(mdata
, name
);
500 g_hash_table_insert(mdata
->markers_hash
, (gpointer
)(gulong
)name
,
501 (gpointer
)(gulong
)id
);
503 struct marker_info
*iter
;
504 for (iter
= head
; iter
!= NULL
; iter
= iter
->next
)
505 if (iter
->name
== name
)
508 g_hash_table_replace(mdata
->markers_hash
, (gpointer
)(gulong
)name
,
509 (gpointer
)(gulong
)id
);
516 struct marker_data
*allocate_marker_data(void)
518 struct marker_data
*data
;
520 data
= g_new(struct marker_data
, 1);
521 /* Init array to 0 */
522 data
->markers
= g_array_sized_new(FALSE
, TRUE
,
523 sizeof(struct marker_info
), DEFAULT_MARKERS_NUM
);
526 data
->markers_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
527 if (!data
->markers_hash
)
529 data
->markers_format_hash
= g_hash_table_new_full(g_direct_hash
,
530 g_direct_equal
, NULL
, g_free
);
531 if (!data
->markers_format_hash
)
532 goto free_markers_hash
;
537 g_hash_table_destroy(data
->markers_hash
);
539 g_array_free(data
->markers
, TRUE
);
545 void destroy_marker_data(struct marker_data
*data
)
548 struct marker_info
*info
;
549 struct marker_field
*field
;
551 for (i
=0; i
<data
->markers
->len
; i
++) {
552 info
= &g_array_index(data
->markers
, struct marker_info
, i
);
554 for (j
= 0; j
< info
->fields
->len
; j
++) {
555 field
= &g_array_index(info
->fields
, struct marker_field
, j
);
556 g_string_free(field
->fmt
, TRUE
);
558 g_array_free(info
->fields
, TRUE
);
561 g_hash_table_destroy(data
->markers_format_hash
);
562 g_hash_table_destroy(data
->markers_hash
);
563 g_array_free(data
->markers
, TRUE
);