remove files unneeded for lttv
[lttv.git] / lttv / ltt / marker.c
CommitLineData
f2a74ed3 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2007 Mathieu Desnoyers
d2007fbd 3 *
f2a74ed3 4 * Complete rewrite from the original version made by XangXiu Yang.
5 *
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.
9 *
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.
14 *
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.
d2007fbd 19 */
20
f2a74ed3 21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
d2007fbd 25#include <glib.h>
3c165eaf 26#include <stdio.h>
27#include <string.h>
28#include <errno.h>
d2007fbd 29#include <ltt/compiler.h>
bb38a290 30#include <ltt/marker.h>
3c165eaf 31#include <ltt/ltt-private.h>
d2007fbd 32
33#define DEFAULT_MARKERS_NUM 100
3c165eaf 34#define DEFAULT_FIELDS_NUM 1
35#define MAX_NAME_LEN 1024
d2007fbd 36
3c165eaf 37static inline const char *parse_trace_type(struct marker_info *info,
38 const char *fmt,
39 char *trace_size, enum ltt_type *trace_type,
40 unsigned long *attributes)
41{
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 */
46
47 /* parse attributes. */
48 repeat:
49 switch (*fmt) {
3c165eaf 50 case 'n':
51 *attributes |= LTT_ATTRIBUTE_NETWORK_BYTE_ORDER;
52 ++fmt;
53 goto repeat;
54 }
55
56 /* get the conversion qualifier */
57 qualifier = -1;
58 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
59 *fmt =='Z' || *fmt == 'z' || *fmt == 't' ||
60 *fmt == 'S' || *fmt == '1' || *fmt == '2' ||
8d2ebd3d 61 *fmt == '4' || *fmt == '8') {
3c165eaf 62 qualifier = *fmt;
63 ++fmt;
64 if (qualifier == 'l' && *fmt == 'l') {
65 qualifier = 'L';
66 ++fmt;
67 }
68 }
69
70 switch (*fmt) {
71 case 'c':
72 *trace_type = LTT_TYPE_UNSIGNED_INT;
73 *trace_size = sizeof(char);
74 goto parse_end;
75 case 's':
76 *trace_type = LTT_TYPE_STRING;
77 goto parse_end;
78 case 'p':
91346f59 79 *trace_type = LTT_TYPE_POINTER;
3c165eaf 80 *trace_size = info->pointer_size;
81 goto parse_end;
82 case 'd':
83 case 'i':
84 *trace_type = LTT_TYPE_SIGNED_INT;
85 break;
86 case 'o':
87 case 'u':
88 case 'x':
89 case 'X':
90 *trace_type = LTT_TYPE_UNSIGNED_INT;
91 break;
92 default:
93 if (!*fmt)
94 --fmt;
95 goto parse_end;
96 }
97 switch (qualifier) {
98 case 'L':
99 *trace_size = sizeof(long long);
100 break;
101 case 'l':
102 *trace_size = info->long_size;
103 break;
104 case 'Z':
105 case 'z':
106 *trace_size = info->size_t_size;
107 break;
108 case 't':
109 *trace_size = info->pointer_size;
110 break;
111 case 'h':
112 *trace_size = sizeof(short);
113 break;
114 case '1':
115 *trace_size = sizeof(uint8_t);
116 break;
117 case '2':
118 *trace_size = sizeof(guint16);
119 break;
120 case '4':
121 *trace_size = sizeof(uint32_t);
122 break;
123 case '8':
124 *trace_size = sizeof(uint64_t);
125 break;
126 default:
127 *trace_size = info->int_size;
128 }
129
130parse_end:
131 return fmt;
132}
133
134/*
135 * Restrictions:
136 * Field width and precision are *not* supported.
137 * %n not supported.
138 */
139__attribute__((no_instrument_function))
140static inline const char *parse_c_type(struct marker_info *info,
141 const char *fmt,
4d683428 142 char *c_size, enum ltt_type *c_type, GString *field_fmt)
3c165eaf 143{
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 */
148
149 /* process flags : ignore standard print formats for now. */
150 repeat:
151 switch (*fmt) {
152 case '-':
153 case '+':
154 case ' ':
155 case '#':
156 case '0':
4d683428 157 g_string_append_c(field_fmt, *fmt);
3c165eaf 158 ++fmt;
159 goto repeat;
160 }
161
162 /* get the conversion qualifier */
163 qualifier = -1;
164 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
165 *fmt =='Z' || *fmt == 'z' || *fmt == 't' ||
166 *fmt == 'S') {
167 qualifier = *fmt;
168 ++fmt;
169 if (qualifier == 'l' && *fmt == 'l') {
170 qualifier = 'L';
171 ++fmt;
172 }
173 }
174
175 switch (*fmt) {
176 case 'c':
177 *c_type = LTT_TYPE_UNSIGNED_INT;
178 *c_size = sizeof(unsigned char);
4d683428 179 g_string_append_c(field_fmt, *fmt);
3c165eaf 180 goto parse_end;
181 case 's':
182 *c_type = LTT_TYPE_STRING;
183 goto parse_end;
184 case 'p':
91346f59 185 *c_type = LTT_TYPE_POINTER;
3c165eaf 186 *c_size = info->pointer_size;
187 goto parse_end;
188 case 'd':
189 case 'i':
190 *c_type = LTT_TYPE_SIGNED_INT;
4d683428 191 g_string_append_c(field_fmt, 'l');
192 g_string_append_c(field_fmt, 'l');
193 g_string_append_c(field_fmt, *fmt);
3c165eaf 194 break;
195 case 'o':
196 case 'u':
197 case 'x':
198 case 'X':
4d683428 199 g_string_append_c(field_fmt, 'l');
200 g_string_append_c(field_fmt, 'l');
201 g_string_append_c(field_fmt, *fmt);
3c165eaf 202 *c_type = LTT_TYPE_UNSIGNED_INT;
203 break;
204 default:
205 if (!*fmt)
206 --fmt;
207 goto parse_end;
208 }
209 switch (qualifier) {
210 case 'L':
211 *c_size = sizeof(long long);
212 break;
213 case 'l':
214 *c_size = info->long_size;
215 break;
216 case 'Z':
217 case 'z':
218 *c_size = info->size_t_size;
219 break;
220 case 't':
221 *c_size = info->pointer_size;
222 break;
223 case 'h':
224 *c_size = sizeof(short);
225 break;
226 default:
227 *c_size = info->int_size;
228 }
229
230parse_end:
231 return fmt;
232}
233
234static 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,
4d683428 238 unsigned int field_count, GString *field_fmt)
3c165eaf 239{
240 struct marker_field *field;
241 char tmpname[MAX_NAME_LEN];
242
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);
246 if (name)
247 field->name = g_quark_from_string(name);
248 else {
249 snprintf(tmpname, MAX_NAME_LEN-1, "field %u", field_count);
250 field->name = g_quark_from_string(tmpname);
251 }
252 field->type = trace_type;
4d683428 253 field->fmt = g_string_new(field_fmt->str);
3c165eaf 254
255 switch (trace_type) {
256 case LTT_TYPE_SIGNED_INT:
257 case LTT_TYPE_UNSIGNED_INT:
7f440a66 258 case LTT_TYPE_POINTER:
3c165eaf 259 field->size = trace_size;
260 field->alignment = trace_size;
2fc874ab 261 info->largest_align = max((guint8)field->alignment,
262 (guint8)info->largest_align);
3c165eaf 263 field->attributes = attributes;
264 if (offset == -1) {
265 field->offset = -1;
266 field->static_offset = 0;
267 return -1;
268 } else {
269 field->offset = offset + ltt_align(offset, field->alignment,
270 info->alignment);
271 field->static_offset = 1;
272 return field->offset + trace_size;
273 }
274 case LTT_TYPE_STRING:
275 field->offset = offset;
276 field->size = 0; /* Variable length, size is 0 */
277 field->alignment = 1;
278 if (offset == -1)
279 field->static_offset = 0;
280 else
281 field->static_offset = 1;
282 return -1;
283 default:
2fc874ab 284 g_error("Unexpected type");
3c165eaf 285 return 0;
286 }
287}
288
289long marker_update_fields_offsets(struct marker_info *info, const char *data)
290{
291 struct marker_field *field;
292 unsigned int i;
293 long offset = 0;
294
256a5b3a 295 /* Find the last field with a static offset, then update from there. */
296 for (i = info->fields->len - 1; i >= 0; i--) {
3c165eaf 297 field = &g_array_index(info->fields, struct marker_field, i);
256a5b3a 298 if (field->static_offset) {
299 offset = field->offset;
300 break;
301 }
302 }
3c165eaf 303
256a5b3a 304 for (; i < info->fields->len; i++) {
305 field = &g_array_index(info->fields, struct marker_field, i);
3c165eaf 306
307 switch (field->type) {
308 case LTT_TYPE_SIGNED_INT:
309 case LTT_TYPE_UNSIGNED_INT:
7f440a66 310 case LTT_TYPE_POINTER:
3c165eaf 311 field->offset = offset + ltt_align(offset, field->alignment,
312 info->alignment);
313 offset = field->offset + field->size;
314 break;
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.
319 break;
320 default:
2fc874ab 321 g_error("Unexpected type");
3c165eaf 322 return -1;
323 }
324 }
325 return offset;
326}
327
328static void format_parse(const char *fmt, struct marker_info *info)
329{
330 char trace_size = 0, c_size = 0; /*
331 * 0 (unset), 1, 2, 4, 8 bytes.
332 */
333 enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
334 unsigned long attributes = 0;
335 long offset = 0;
336 const char *name_begin = NULL, *name_end = NULL;
337 char *name = NULL;
338 unsigned int field_count = 1;
4d683428 339 GString *field_fmt = g_string_new("");
3c165eaf 340
2e13d6af 341 name_begin = fmt;
3c165eaf 342 for (; *fmt ; ++fmt) {
343 switch (*fmt) {
344 case '#':
345 /* tracetypes (#) */
346 ++fmt; /* skip first '#' */
4d683428 347 if (*fmt == '#') { /* Escaped ## */
348 g_string_append_c(field_fmt, *fmt);
349 g_string_append_c(field_fmt, *fmt);
3c165eaf 350 break;
4d683428 351 }
3c165eaf 352 attributes = 0;
353 fmt = parse_trace_type(info, fmt, &trace_size, &trace_type,
354 &attributes);
355 break;
356 case '%':
357 /* c types (%) */
4d683428 358 g_string_append_c(field_fmt, *fmt);
3c165eaf 359 ++fmt; /* skip first '%' */
4d683428 360 if (*fmt == '%') { /* Escaped %% */
361 g_string_append_c(field_fmt, *fmt);
3c165eaf 362 break;
4d683428 363 }
364 fmt = parse_c_type(info, fmt, &c_size, &c_type, field_fmt);
3c165eaf 365 /*
366 * Output c types if no trace types has been
367 * specified.
368 */
369 if (!trace_size)
370 trace_size = c_size;
371 if (trace_type == LTT_TYPE_NONE)
372 trace_type = c_type;
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,
4d683428 377 trace_type, c_size, c_type, attributes, field_count++,
378 field_fmt);
3c165eaf 379 trace_size = c_size = 0;
380 trace_type = c_size = LTT_TYPE_NONE;
4d683428 381 g_string_truncate(field_fmt, 0);
3c165eaf 382 attributes = 0;
383 name_begin = NULL;
384 if (name) {
385 g_free(name);
386 name = NULL;
387 }
388 break;
389 case ' ':
4d683428 390 g_string_truncate(field_fmt, 0);
565460ea 391 if (!name_end && name_begin) {
3c165eaf 392 name_end = fmt;
393 if (name)
394 g_free(name);
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';
398 }
399 break; /* Skip white spaces */
400 default:
4d683428 401 g_string_append_c(field_fmt, *fmt);
565460ea 402 if (!name_begin) {
3c165eaf 403 name_begin = fmt;
404 name_end = NULL;
405 }
406 }
407 }
408 info->size = offset;
409 if (name)
410 g_free(name);
4d683428 411 g_string_free(field_fmt, TRUE);
3c165eaf 412}
413
414int marker_parse_format(const char *format, struct marker_info *info)
415{
416 if (info->fields)
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);
2e13d6af 421 return 0;
3c165eaf 422}
423
750eb11a 424int marker_format_event(LttTrace *trace, GQuark channel, GQuark name,
425 const char *format)
d2007fbd 426{
427 struct marker_info *info;
750eb11a 428 struct marker_data *mdata;
c09a11e9 429 char *fquery;
430 char *fcopy;
750eb11a 431 GArray *group;
432
433 group = g_datalist_id_get_data(&trace->tracefiles, channel);
0919a063 434 if (!group)
435 return -ENOENT;
750eb11a 436 g_assert(group->len > 0);
437 mdata = g_array_index (group, LttTracefile, 0).mdata;
438
439 fquery = marker_get_format_from_name(mdata, name);
37e04c8b 440 if (fquery) {
c09a11e9 441 if (strcmp(fquery, format) != 0)
750eb11a 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));
37e04c8b 445 else
446 return 0; /* Already exists. Nothing to do. */
447 }
c09a11e9 448 fcopy = g_new(char, strlen(format)+1);
449 strcpy(fcopy, format);
750eb11a 450 g_hash_table_insert(mdata->markers_format_hash, (gpointer)(gulong)name,
c09a11e9 451 (gpointer)fcopy);
452
750eb11a 453 info = marker_get_info_from_name(mdata, name);
3c165eaf 454 for (; info != NULL; info = info->next) {
c09a11e9 455 info->format = fcopy;
3c165eaf 456 if (marker_parse_format(format, info))
750eb11a 457 g_error("Error parsing marker format \"%s\" for marker \"%.s.%s\"",
458 format, g_quark_to_string(channel), g_quark_to_string(name));
3c165eaf 459 }
03dab2c1 460 return 0;
d2007fbd 461}
462
750eb11a 463int marker_id_event(LttTrace *trace, GQuark channel, GQuark name, guint16 id,
3c165eaf 464 uint8_t int_size, uint8_t long_size, uint8_t pointer_size,
465 uint8_t size_t_size, uint8_t alignment)
d2007fbd 466{
750eb11a 467 struct marker_data *mdata;
3c165eaf 468 struct marker_info *info, *head;
03dab2c1 469 int found = 0;
750eb11a 470 GArray *group;
471
472 g_debug("Add channel %s event %s %hu\n", g_quark_to_string(channel),
473 g_quark_to_string(name), id);
474
475 group = g_datalist_id_get_data(&trace->tracefiles, channel);
0919a063 476 if (!group)
477 return -ENOENT;
750eb11a 478 g_assert(group->len > 0);
479 mdata = g_array_index (group, LttTracefile, 0).mdata;
d2007fbd 480
750eb11a 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);
3c165eaf 485 info->name = name;
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;
dcf96842 491 info->fields = NULL;
3c165eaf 492 info->next = NULL;
750eb11a 493 info->format = marker_get_format_from_name(mdata, name);
2fc874ab 494 info->largest_align = 1;
c09a11e9 495 if (info->format && marker_parse_format(info->format, info))
750eb11a 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);
3c165eaf 499 if (!head)
750eb11a 500 g_hash_table_insert(mdata->markers_hash, (gpointer)(gulong)name,
abc34be7 501 (gpointer)(gulong)id);
d7913a10 502 else {
03dab2c1 503 struct marker_info *iter;
504 for (iter = head; iter != NULL; iter = iter->next)
505 if (iter->name == name)
506 found = 1;
507 if (!found) {
750eb11a 508 g_hash_table_replace(mdata->markers_hash, (gpointer)(gulong)name,
abc34be7 509 (gpointer)(gulong)id);
03dab2c1 510 info->next = head;
511 }
d7913a10 512 }
03dab2c1 513 return 0;
d2007fbd 514}
515
750eb11a 516struct marker_data *allocate_marker_data(void)
d2007fbd 517{
750eb11a 518 struct marker_data *data;
519
520 data = g_new(struct marker_data, 1);
d2007fbd 521 /* Init array to 0 */
750eb11a 522 data->markers = g_array_sized_new(FALSE, TRUE,
d2007fbd 523 sizeof(struct marker_info), DEFAULT_MARKERS_NUM);
750eb11a 524 if (!data->markers)
525 goto free_data;
526 data->markers_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
527 if (!data->markers_hash)
528 goto free_markers;
529 data->markers_format_hash = g_hash_table_new_full(g_direct_hash,
c09a11e9 530 g_direct_equal, NULL, g_free);
750eb11a 531 if (!data->markers_format_hash)
532 goto free_markers_hash;
533 return data;
534
535 /* error handling */
536free_markers_hash:
537 g_hash_table_destroy(data->markers_hash);
538free_markers:
539 g_array_free(data->markers, TRUE);
540free_data:
541 g_free(data);
542 return NULL;
d2007fbd 543}
544
750eb11a 545void destroy_marker_data(struct marker_data *data)
d2007fbd 546{
4d683428 547 unsigned int i, j;
d2007fbd 548 struct marker_info *info;
4d683428 549 struct marker_field *field;
d2007fbd 550
750eb11a 551 for (i=0; i<data->markers->len; i++) {
552 info = &g_array_index(data->markers, struct marker_info, i);
4d683428 553 if (info->fields) {
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);
557 }
3c165eaf 558 g_array_free(info->fields, TRUE);
4d683428 559 }
d2007fbd 560 }
750eb11a 561 g_hash_table_destroy(data->markers_format_hash);
562 g_hash_table_destroy(data->markers_hash);
563 g_array_free(data->markers, TRUE);
564 g_free(data);
d2007fbd 565}
This page took 0.05632 seconds and 4 git commands to generate.