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
)
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. */
165 /* get the conversion qualifier */
167 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' ||
168 *fmt
=='Z' || *fmt
== 'z' || *fmt
== 't' ||
172 if (qualifier
== 'l' && *fmt
== 'l') {
180 *c_type
= LTT_TYPE_UNSIGNED_INT
;
181 *c_size
= sizeof(unsigned char);
184 *c_type
= LTT_TYPE_STRING
;
187 *c_type
= LTT_TYPE_POINTER
;
188 *c_size
= info
->pointer_size
;
192 *c_type
= LTT_TYPE_SIGNED_INT
;
198 *c_type
= LTT_TYPE_UNSIGNED_INT
;
207 *c_size
= sizeof(long long);
210 *c_size
= info
->long_size
;
214 *c_size
= info
->size_t_size
;
217 *c_size
= info
->pointer_size
;
220 *c_size
= sizeof(short);
223 *c_size
= info
->int_size
;
230 static inline long add_type(struct marker_info
*info
,
231 long offset
, const char *name
,
232 char trace_size
, enum ltt_type trace_type
,
233 char c_size
, enum ltt_type c_type
, unsigned long attributes
,
234 unsigned int field_count
)
236 struct marker_field
*field
;
237 char tmpname
[MAX_NAME_LEN
];
239 info
->fields
= g_array_set_size(info
->fields
, info
->fields
->len
+1);
240 field
= &g_array_index(info
->fields
, struct marker_field
,
241 info
->fields
->len
-1);
243 field
->name
= g_quark_from_string(name
);
245 snprintf(tmpname
, MAX_NAME_LEN
-1, "field %u", field_count
);
246 field
->name
= g_quark_from_string(tmpname
);
248 field
->type
= trace_type
;
250 switch (trace_type
) {
251 case LTT_TYPE_SIGNED_INT
:
252 case LTT_TYPE_UNSIGNED_INT
:
253 case LTT_TYPE_POINTER
:
254 field
->size
= trace_size
;
255 field
->alignment
= trace_size
;
256 field
->attributes
= attributes
;
259 field
->static_offset
= 0;
262 field
->offset
= offset
+ ltt_align(offset
, field
->alignment
,
264 field
->static_offset
= 1;
265 return field
->offset
+ trace_size
;
267 case LTT_TYPE_STRING
:
268 field
->offset
= offset
;
269 field
->size
= 0; /* Variable length, size is 0 */
270 field
->alignment
= 1;
272 field
->static_offset
= 0;
274 field
->static_offset
= 1;
277 g_error("Unexpected type"); //FIXME: compact type
282 long marker_update_fields_offsets(struct marker_info
*info
, const char *data
)
284 struct marker_field
*field
;
288 /* Find the last field with a static offset, then update from there. */
289 for (i
= info
->fields
->len
- 1; i
>= 0; i
--) {
290 field
= &g_array_index(info
->fields
, struct marker_field
, i
);
291 if (field
->static_offset
) {
292 offset
= field
->offset
;
297 for (; i
< info
->fields
->len
; i
++) {
298 field
= &g_array_index(info
->fields
, struct marker_field
, i
);
300 switch (field
->type
) {
301 case LTT_TYPE_SIGNED_INT
:
302 case LTT_TYPE_UNSIGNED_INT
:
303 case LTT_TYPE_POINTER
:
304 field
->offset
= offset
+ ltt_align(offset
, field
->alignment
,
306 offset
= field
->offset
+ field
->size
;
308 case LTT_TYPE_STRING
:
309 field
->offset
= offset
;
310 offset
= offset
+ strlen(&data
[offset
]) + 1;
311 // not aligning on pointer size, breaking genevent backward compatibility.
314 g_error("Unexpected type"); //FIXME: compact type
321 static void format_parse(const char *fmt
, struct marker_info
*info
)
323 char trace_size
= 0, c_size
= 0; /*
324 * 0 (unset), 1, 2, 4, 8 bytes.
326 enum ltt_type trace_type
= LTT_TYPE_NONE
, c_type
= LTT_TYPE_NONE
;
327 unsigned long attributes
= 0;
329 const char *name_begin
= NULL
, *name_end
= NULL
;
331 unsigned int field_count
= 1;
334 for (; *fmt
; ++fmt
) {
338 ++fmt
; /* skip first '#' */
339 if (*fmt
== '#') /* Escaped ## */
342 fmt
= parse_trace_type(info
, fmt
, &trace_size
, &trace_type
,
347 ++fmt
; /* skip first '%' */
348 if (*fmt
== '%') /* Escaped %% */
350 fmt
= parse_c_type(info
, fmt
, &c_size
, &c_type
);
352 * Output c types if no trace types has been
357 if (trace_type
== LTT_TYPE_NONE
)
359 if (c_type
== LTT_TYPE_STRING
)
360 trace_type
= LTT_TYPE_STRING
;
361 /* perform trace write */
362 offset
= add_type(info
, offset
, name
, trace_size
,
363 trace_type
, c_size
, c_type
, attributes
, field_count
++);
364 trace_size
= c_size
= 0;
365 trace_type
= c_size
= LTT_TYPE_NONE
;
374 if (!name_end
&& name_begin
) {
378 name
= g_new(char, name_end
- name_begin
+ 1);
379 memcpy(name
, name_begin
, name_end
- name_begin
);
380 name
[name_end
- name_begin
] = '\0';
382 break; /* Skip white spaces */
395 int marker_parse_format(const char *format
, struct marker_info
*info
)
398 g_array_free(info
->fields
, TRUE
);
399 info
->fields
= g_array_sized_new(FALSE
, TRUE
,
400 sizeof(struct marker_field
), DEFAULT_FIELDS_NUM
);
401 format_parse(format
, info
);
405 int marker_format_event(LttTrace
*trace
, GQuark name
, const char *format
)
407 struct marker_info
*info
;
411 fquery
= marker_get_format_from_name(trace
, name
);
413 if (strcmp(fquery
, format
) != 0)
414 g_error("Marker format mismatch \"%s\" vs \"%s\" for marker %s. "
415 "Kernel issue.", fquery
, format
, g_quark_to_string(name
));
417 return 0; /* Already exists. Nothing to do. */
419 fcopy
= g_new(char, strlen(format
)+1);
420 strcpy(fcopy
, format
);
421 g_hash_table_insert(trace
->markers_format_hash
, (gpointer
)(gulong
)name
,
424 info
= marker_get_info_from_name(trace
, name
);
425 for (; info
!= NULL
; info
= info
->next
) {
426 info
->format
= fcopy
;
427 if (marker_parse_format(format
, info
))
428 g_error("Error parsing marker format \"%s\" for marker \"%s\"", format
,
429 g_quark_to_string(name
));
434 int marker_id_event(LttTrace
*trace
, GQuark name
, guint16 id
,
435 uint8_t int_size
, uint8_t long_size
, uint8_t pointer_size
,
436 uint8_t size_t_size
, uint8_t alignment
)
438 struct marker_info
*info
, *head
;
441 if (trace
->markers
->len
<= id
)
442 trace
->markers
= g_array_set_size(trace
->markers
,
443 max(trace
->markers
->len
* 2, id
+ 1));
444 info
= &g_array_index(trace
->markers
, struct marker_info
, id
);
446 info
->int_size
= int_size
;
447 info
->long_size
= long_size
;
448 info
->pointer_size
= pointer_size
;
449 info
->size_t_size
= size_t_size
;
450 info
->alignment
= alignment
;
453 info
->format
= marker_get_format_from_name(trace
, name
);
454 if (info
->format
&& marker_parse_format(info
->format
, info
))
455 g_error("Error parsing marker format \"%s\" for marker \"%s\"",
456 info
->format
, g_quark_to_string(name
));
457 head
= marker_get_info_from_name(trace
, name
);
459 g_hash_table_insert(trace
->markers_hash
, (gpointer
)(gulong
)name
,
460 (gpointer
)(gulong
)id
);
462 struct marker_info
*iter
;
463 for (iter
= head
; iter
!= NULL
; iter
= iter
->next
)
464 if (iter
->name
== name
)
467 g_hash_table_replace(trace
->markers_hash
, (gpointer
)(gulong
)name
,
468 (gpointer
)(gulong
)id
);
475 int allocate_marker_data(LttTrace
*trace
)
477 /* Init array to 0 */
478 trace
->markers
= g_array_sized_new(FALSE
, TRUE
,
479 sizeof(struct marker_info
), DEFAULT_MARKERS_NUM
);
482 trace
->markers_hash
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
483 if (!trace
->markers_hash
)
485 trace
->markers_format_hash
= g_hash_table_new_full(g_direct_hash
,
486 g_direct_equal
, NULL
, g_free
);
487 if (!trace
->markers_hash
)
492 void destroy_marker_data(LttTrace
*trace
)
495 struct marker_info
*info
;
497 for (i
=0; i
<trace
->markers
->len
; i
++) {
498 info
= &g_array_index(trace
->markers
, struct marker_info
, i
);
500 g_array_free(info
->fields
, TRUE
);
502 g_array_free(trace
->markers
, TRUE
);
503 g_hash_table_destroy(trace
->markers_hash
);
504 g_hash_table_destroy(trace
->markers_format_hash
);