add pointer type
[lttv.git] / ltt / branches / poly / 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) {
50 case 'b':
51 *attributes |= LTT_ATTRIBUTE_COMPACT;
52 ++fmt;
53 goto repeat;
54 case 'n':
55 *attributes |= LTT_ATTRIBUTE_NETWORK_BYTE_ORDER;
56 ++fmt;
57 goto repeat;
58 }
59
60 /* get the conversion qualifier */
61 qualifier = -1;
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) {
66 qualifier = *fmt;
67 ++fmt;
68 if (qualifier == 'l' && *fmt == 'l') {
69 qualifier = 'L';
70 ++fmt;
71 }
72 }
73
74 switch (*fmt) {
75 case 'c':
76 *trace_type = LTT_TYPE_UNSIGNED_INT;
77 *trace_size = sizeof(char);
78 goto parse_end;
79 case 's':
80 *trace_type = LTT_TYPE_STRING;
81 goto parse_end;
82 case 'p':
91346f59 83 *trace_type = LTT_TYPE_POINTER;
3c165eaf 84 *trace_size = info->pointer_size;
85 goto parse_end;
86 case 'd':
87 case 'i':
88 *trace_type = LTT_TYPE_SIGNED_INT;
89 break;
90 case 'o':
91 case 'u':
92 case 'x':
93 case 'X':
94 *trace_type = LTT_TYPE_UNSIGNED_INT;
95 break;
96 default:
97 if (!*fmt)
98 --fmt;
99 goto parse_end;
100 }
101 switch (qualifier) {
102 case 'L':
103 *trace_size = sizeof(long long);
104 break;
105 case 'l':
106 *trace_size = info->long_size;
107 break;
108 case 'Z':
109 case 'z':
110 *trace_size = info->size_t_size;
111 break;
112 case 't':
113 *trace_size = info->pointer_size;
114 break;
115 case 'h':
116 *trace_size = sizeof(short);
117 break;
118 case '1':
119 *trace_size = sizeof(uint8_t);
120 break;
121 case '2':
122 *trace_size = sizeof(guint16);
123 break;
124 case '4':
125 *trace_size = sizeof(uint32_t);
126 break;
127 case '8':
128 *trace_size = sizeof(uint64_t);
129 break;
130 default:
131 *trace_size = info->int_size;
132 }
133
134parse_end:
135 return fmt;
136}
137
138/*
139 * Restrictions:
140 * Field width and precision are *not* supported.
141 * %n not supported.
142 */
143__attribute__((no_instrument_function))
144static inline const char *parse_c_type(struct marker_info *info,
145 const char *fmt,
146 char *c_size, enum ltt_type *c_type)
147{
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 */
152
153 /* process flags : ignore standard print formats for now. */
154 repeat:
155 switch (*fmt) {
156 case '-':
157 case '+':
158 case ' ':
159 case '#':
160 case '0':
161 ++fmt;
162 goto repeat;
163 }
164
165 /* get the conversion qualifier */
166 qualifier = -1;
167 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
168 *fmt =='Z' || *fmt == 'z' || *fmt == 't' ||
169 *fmt == 'S') {
170 qualifier = *fmt;
171 ++fmt;
172 if (qualifier == 'l' && *fmt == 'l') {
173 qualifier = 'L';
174 ++fmt;
175 }
176 }
177
178 switch (*fmt) {
179 case 'c':
180 *c_type = LTT_TYPE_UNSIGNED_INT;
181 *c_size = sizeof(unsigned char);
182 goto parse_end;
183 case 's':
184 *c_type = LTT_TYPE_STRING;
185 goto parse_end;
186 case 'p':
91346f59 187 *c_type = LTT_TYPE_POINTER;
3c165eaf 188 *c_size = info->pointer_size;
189 goto parse_end;
190 case 'd':
191 case 'i':
192 *c_type = LTT_TYPE_SIGNED_INT;
193 break;
194 case 'o':
195 case 'u':
196 case 'x':
197 case 'X':
198 *c_type = LTT_TYPE_UNSIGNED_INT;
199 break;
200 default:
201 if (!*fmt)
202 --fmt;
203 goto parse_end;
204 }
205 switch (qualifier) {
206 case 'L':
207 *c_size = sizeof(long long);
208 break;
209 case 'l':
210 *c_size = info->long_size;
211 break;
212 case 'Z':
213 case 'z':
214 *c_size = info->size_t_size;
215 break;
216 case 't':
217 *c_size = info->pointer_size;
218 break;
219 case 'h':
220 *c_size = sizeof(short);
221 break;
222 default:
223 *c_size = info->int_size;
224 }
225
226parse_end:
227 return fmt;
228}
229
230static 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)
235{
236 struct marker_field *field;
237 char tmpname[MAX_NAME_LEN];
238
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);
242 if (name)
243 field->name = g_quark_from_string(name);
244 else {
245 snprintf(tmpname, MAX_NAME_LEN-1, "field %u", field_count);
246 field->name = g_quark_from_string(tmpname);
247 }
248 field->type = trace_type;
249
250 switch (trace_type) {
251 case LTT_TYPE_SIGNED_INT:
252 case LTT_TYPE_UNSIGNED_INT:
253 field->size = trace_size;
254 field->alignment = trace_size;
255 field->attributes = attributes;
256 if (offset == -1) {
257 field->offset = -1;
258 field->static_offset = 0;
259 return -1;
260 } else {
261 field->offset = offset + ltt_align(offset, field->alignment,
262 info->alignment);
263 field->static_offset = 1;
264 return field->offset + trace_size;
265 }
266 case LTT_TYPE_STRING:
267 field->offset = offset;
268 field->size = 0; /* Variable length, size is 0 */
269 field->alignment = 1;
270 if (offset == -1)
271 field->static_offset = 0;
272 else
273 field->static_offset = 1;
274 return -1;
275 default:
276 g_error("Unexpected type"); //FIXME: compact type
277 return 0;
278 }
279}
280
281long marker_update_fields_offsets(struct marker_info *info, const char *data)
282{
283 struct marker_field *field;
284 unsigned int i;
285 long offset = 0;
286
256a5b3a 287 /* Find the last field with a static offset, then update from there. */
288 for (i = info->fields->len - 1; i >= 0; i--) {
3c165eaf 289 field = &g_array_index(info->fields, struct marker_field, i);
256a5b3a 290 if (field->static_offset) {
291 offset = field->offset;
292 break;
293 }
294 }
3c165eaf 295
256a5b3a 296 for (; i < info->fields->len; i++) {
297 field = &g_array_index(info->fields, struct marker_field, i);
3c165eaf 298
299 switch (field->type) {
300 case LTT_TYPE_SIGNED_INT:
301 case LTT_TYPE_UNSIGNED_INT:
302 field->offset = offset + ltt_align(offset, field->alignment,
303 info->alignment);
304 offset = field->offset + field->size;
305 break;
306 case LTT_TYPE_STRING:
307 field->offset = offset;
308 offset = offset + strlen(&data[offset]) + 1;
309 // not aligning on pointer size, breaking genevent backward compatibility.
310 break;
311 default:
312 g_error("Unexpected type"); //FIXME: compact type
313 return -1;
314 }
315 }
316 return offset;
317}
318
319static void format_parse(const char *fmt, struct marker_info *info)
320{
321 char trace_size = 0, c_size = 0; /*
322 * 0 (unset), 1, 2, 4, 8 bytes.
323 */
324 enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
325 unsigned long attributes = 0;
326 long offset = 0;
327 const char *name_begin = NULL, *name_end = NULL;
328 char *name = NULL;
329 unsigned int field_count = 1;
330
2e13d6af 331 name_begin = fmt;
3c165eaf 332 for (; *fmt ; ++fmt) {
333 switch (*fmt) {
334 case '#':
335 /* tracetypes (#) */
336 ++fmt; /* skip first '#' */
337 if (*fmt == '#') /* Escaped ## */
338 break;
339 attributes = 0;
340 fmt = parse_trace_type(info, fmt, &trace_size, &trace_type,
341 &attributes);
342 break;
343 case '%':
344 /* c types (%) */
345 ++fmt; /* skip first '%' */
346 if (*fmt == '%') /* Escaped %% */
347 break;
348 fmt = parse_c_type(info, fmt, &c_size, &c_type);
349 /*
350 * Output c types if no trace types has been
351 * specified.
352 */
353 if (!trace_size)
354 trace_size = c_size;
355 if (trace_type == LTT_TYPE_NONE)
356 trace_type = c_type;
357 if (c_type == LTT_TYPE_STRING)
358 trace_type = LTT_TYPE_STRING;
359 /* perform trace write */
360 offset = add_type(info, offset, name, trace_size,
361 trace_type, c_size, c_type, attributes, field_count++);
362 trace_size = c_size = 0;
363 trace_type = c_size = LTT_TYPE_NONE;
364 attributes = 0;
365 name_begin = NULL;
366 if (name) {
367 g_free(name);
368 name = NULL;
369 }
370 break;
371 case ' ':
565460ea 372 if (!name_end && name_begin) {
3c165eaf 373 name_end = fmt;
374 if (name)
375 g_free(name);
376 name = g_new(char, name_end - name_begin + 1);
377 memcpy(name, name_begin, name_end - name_begin);
378 name[name_end - name_begin] = '\0';
379 }
380 break; /* Skip white spaces */
381 default:
565460ea 382 if (!name_begin) {
3c165eaf 383 name_begin = fmt;
384 name_end = NULL;
385 }
386 }
387 }
388 info->size = offset;
389 if (name)
390 g_free(name);
391}
392
393int marker_parse_format(const char *format, struct marker_info *info)
394{
395 if (info->fields)
396 g_array_free(info->fields, TRUE);
397 info->fields = g_array_sized_new(FALSE, TRUE,
398 sizeof(struct marker_field), DEFAULT_FIELDS_NUM);
399 format_parse(format, info);
2e13d6af 400 return 0;
3c165eaf 401}
402
403int marker_format_event(LttTrace *trace, GQuark name, const char *format)
d2007fbd 404{
405 struct marker_info *info;
406
407 info = g_hash_table_lookup(trace->markers_hash, (gconstpointer)name);
408 if (!info)
2e13d6af 409 g_error("Got marker format \"%s\", but marker name \"%s\" has no ID yet. "
d2007fbd 410 "Kernel issue.",
411 format, name);
3c165eaf 412 for (; info != NULL; info = info->next) {
413 if (info->format)
414 g_free(info->format);
415 info->format = g_new(char, strlen(format)+1);
416 strcpy(info->format, format);
417 if (marker_parse_format(format, info))
2e13d6af 418 g_error("Error parsing marker format \"%s\" for marker \"%s\"", format,
3c165eaf 419 g_quark_to_string(name));
420 }
03dab2c1 421 return 0;
d2007fbd 422}
423
3c165eaf 424int marker_id_event(LttTrace *trace, GQuark name, guint16 id,
425 uint8_t int_size, uint8_t long_size, uint8_t pointer_size,
426 uint8_t size_t_size, uint8_t alignment)
d2007fbd 427{
3c165eaf 428 struct marker_info *info, *head;
03dab2c1 429 int found = 0;
d2007fbd 430
c7146c5c 431 if (trace->markers->len <= id)
d2007fbd 432 trace->markers = g_array_set_size(trace->markers, id+1);
433 info = &g_array_index(trace->markers, struct marker_info, id);
3c165eaf 434 info->name = name;
435 info->int_size = int_size;
436 info->long_size = long_size;
437 info->pointer_size = pointer_size;
438 info->size_t_size = size_t_size;
439 info->alignment = alignment;
440 info->next = NULL;
441 head = g_hash_table_lookup(trace->markers_hash, (gconstpointer)name);
442 if (!head)
443 g_hash_table_insert(trace->markers_hash, (gpointer)name, info);
d7913a10 444 else {
03dab2c1 445 struct marker_info *iter;
446 for (iter = head; iter != NULL; iter = iter->next)
447 if (iter->name == name)
448 found = 1;
449 if (!found) {
450 g_hash_table_replace(trace->markers_hash, (gpointer)name, info);
451 info->next = head;
452 }
d7913a10 453 }
03dab2c1 454 return 0;
d2007fbd 455}
456
457int allocate_marker_data(LttTrace *trace)
458{
459 /* Init array to 0 */
460 trace->markers = g_array_sized_new(FALSE, TRUE,
461 sizeof(struct marker_info), DEFAULT_MARKERS_NUM);
3c165eaf 462 if (!trace->markers)
463 return -ENOMEM;
464 trace->markers_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
465 if (!trace->markers_hash)
466 return -ENOMEM;
467 return 0;
d2007fbd 468}
469
3c165eaf 470void destroy_marker_data(LttTrace *trace)
d2007fbd 471{
472 unsigned int i;
473 struct marker_info *info;
474
475 for (i=0; i<trace->markers->len; i++) {
476 info = &g_array_index(trace->markers, struct marker_info, i);
d2007fbd 477 if (info->format)
478 g_free(info->format);
3c165eaf 479 if (info->fields)
480 g_array_free(info->fields, TRUE);
d2007fbd 481 }
482 g_array_free(trace->markers, TRUE);
483 g_hash_table_destroy(trace->markers_hash);
484}
This page took 0.040923 seconds and 4 git commands to generate.