fix marker-desc
[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
256a5b3a 270 /* Find the last field with a static offset, then update from there. */
271 for (i = info->fields->len - 1; i >= 0; i--) {
3c165eaf 272 field = &g_array_index(info->fields, struct marker_field, i);
256a5b3a 273 if (field->static_offset) {
274 offset = field->offset;
275 break;
276 }
277 }
3c165eaf 278
256a5b3a 279 for (; i < info->fields->len; i++) {
280 field = &g_array_index(info->fields, struct marker_field, i);
3c165eaf 281
282 switch (field->type) {
283 case LTT_TYPE_SIGNED_INT:
284 case LTT_TYPE_UNSIGNED_INT:
285 field->offset = offset + ltt_align(offset, field->alignment,
286 info->alignment);
287 offset = field->offset + field->size;
288 break;
289 case LTT_TYPE_STRING:
290 field->offset = offset;
291 offset = offset + strlen(&data[offset]) + 1;
292 // not aligning on pointer size, breaking genevent backward compatibility.
293 break;
294 default:
295 g_error("Unexpected type"); //FIXME: compact type
296 return -1;
297 }
298 }
299 return offset;
300}
301
302static void format_parse(const char *fmt, struct marker_info *info)
303{
304 char trace_size = 0, c_size = 0; /*
305 * 0 (unset), 1, 2, 4, 8 bytes.
306 */
307 enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE;
308 unsigned long attributes = 0;
309 long offset = 0;
310 const char *name_begin = NULL, *name_end = NULL;
311 char *name = NULL;
312 unsigned int field_count = 1;
313
2e13d6af 314 name_begin = fmt;
3c165eaf 315 for (; *fmt ; ++fmt) {
316 switch (*fmt) {
317 case '#':
318 /* tracetypes (#) */
319 ++fmt; /* skip first '#' */
320 if (*fmt == '#') /* Escaped ## */
321 break;
322 attributes = 0;
323 fmt = parse_trace_type(info, fmt, &trace_size, &trace_type,
324 &attributes);
325 break;
326 case '%':
327 /* c types (%) */
328 ++fmt; /* skip first '%' */
329 if (*fmt == '%') /* Escaped %% */
330 break;
331 fmt = parse_c_type(info, fmt, &c_size, &c_type);
332 /*
333 * Output c types if no trace types has been
334 * specified.
335 */
336 if (!trace_size)
337 trace_size = c_size;
338 if (trace_type == LTT_TYPE_NONE)
339 trace_type = c_type;
340 if (c_type == LTT_TYPE_STRING)
341 trace_type = LTT_TYPE_STRING;
342 /* perform trace write */
343 offset = add_type(info, offset, name, trace_size,
344 trace_type, c_size, c_type, attributes, field_count++);
345 trace_size = c_size = 0;
346 trace_type = c_size = LTT_TYPE_NONE;
347 attributes = 0;
348 name_begin = NULL;
349 if (name) {
350 g_free(name);
351 name = NULL;
352 }
353 break;
354 case ' ':
565460ea 355 if (!name_end && name_begin) {
3c165eaf 356 name_end = fmt;
357 if (name)
358 g_free(name);
359 name = g_new(char, name_end - name_begin + 1);
360 memcpy(name, name_begin, name_end - name_begin);
361 name[name_end - name_begin] = '\0';
362 }
363 break; /* Skip white spaces */
364 default:
565460ea 365 if (!name_begin) {
3c165eaf 366 name_begin = fmt;
367 name_end = NULL;
368 }
369 }
370 }
371 info->size = offset;
372 if (name)
373 g_free(name);
374}
375
376int marker_parse_format(const char *format, struct marker_info *info)
377{
378 if (info->fields)
379 g_array_free(info->fields, TRUE);
380 info->fields = g_array_sized_new(FALSE, TRUE,
381 sizeof(struct marker_field), DEFAULT_FIELDS_NUM);
382 format_parse(format, info);
2e13d6af 383 return 0;
3c165eaf 384}
385
386int marker_format_event(LttTrace *trace, GQuark name, const char *format)
d2007fbd 387{
388 struct marker_info *info;
389
390 info = g_hash_table_lookup(trace->markers_hash, (gconstpointer)name);
391 if (!info)
2e13d6af 392 g_error("Got marker format \"%s\", but marker name \"%s\" has no ID yet. "
d2007fbd 393 "Kernel issue.",
394 format, name);
3c165eaf 395 for (; info != NULL; info = info->next) {
396 if (info->format)
397 g_free(info->format);
398 info->format = g_new(char, strlen(format)+1);
399 strcpy(info->format, format);
400 if (marker_parse_format(format, info))
2e13d6af 401 g_error("Error parsing marker format \"%s\" for marker \"%s\"", format,
3c165eaf 402 g_quark_to_string(name));
403 }
03dab2c1 404 return 0;
d2007fbd 405}
406
3c165eaf 407int marker_id_event(LttTrace *trace, GQuark name, guint16 id,
408 uint8_t int_size, uint8_t long_size, uint8_t pointer_size,
409 uint8_t size_t_size, uint8_t alignment)
d2007fbd 410{
3c165eaf 411 struct marker_info *info, *head;
03dab2c1 412 int found = 0;
d2007fbd 413
414 if (trace->markers->len < id)
415 trace->markers = g_array_set_size(trace->markers, id+1);
416 info = &g_array_index(trace->markers, struct marker_info, id);
3c165eaf 417 info->name = name;
418 info->int_size = int_size;
419 info->long_size = long_size;
420 info->pointer_size = pointer_size;
421 info->size_t_size = size_t_size;
422 info->alignment = alignment;
423 info->next = NULL;
424 head = g_hash_table_lookup(trace->markers_hash, (gconstpointer)name);
425 if (!head)
426 g_hash_table_insert(trace->markers_hash, (gpointer)name, info);
d7913a10 427 else {
03dab2c1 428 struct marker_info *iter;
429 for (iter = head; iter != NULL; iter = iter->next)
430 if (iter->name == name)
431 found = 1;
432 if (!found) {
433 g_hash_table_replace(trace->markers_hash, (gpointer)name, info);
434 info->next = head;
435 }
d7913a10 436 }
03dab2c1 437 return 0;
d2007fbd 438}
439
440int allocate_marker_data(LttTrace *trace)
441{
442 /* Init array to 0 */
443 trace->markers = g_array_sized_new(FALSE, TRUE,
444 sizeof(struct marker_info), DEFAULT_MARKERS_NUM);
3c165eaf 445 if (!trace->markers)
446 return -ENOMEM;
447 trace->markers_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
448 if (!trace->markers_hash)
449 return -ENOMEM;
450 return 0;
d2007fbd 451}
452
3c165eaf 453void destroy_marker_data(LttTrace *trace)
d2007fbd 454{
455 unsigned int i;
456 struct marker_info *info;
457
458 for (i=0; i<trace->markers->len; i++) {
459 info = &g_array_index(trace->markers, struct marker_info, i);
d2007fbd 460 if (info->format)
461 g_free(info->format);
3c165eaf 462 if (info->fields)
463 g_array_free(info->fields, TRUE);
d2007fbd 464 }
465 g_array_free(trace->markers, TRUE);
466 g_hash_table_destroy(trace->markers_hash);
467}
This page took 0.041127 seconds and 4 git commands to generate.