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