Fix integer/float/string read: keep value in definition structure
[babeltrace.git] / formats / ctf / ctf.c
1 /*
2 * BabelTrace - Common Trace Format (CTF)
3 *
4 * Format registration.
5 *
6 * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 */
18
19 #include <babeltrace/format.h>
20 #include <babeltrace/ctf/types.h>
21 #include <babeltrace/ctf/metadata.h>
22 #include <babeltrace/babeltrace.h>
23 #include <inttypes.h>
24 #include <uuid/uuid.h>
25 #include <sys/mman.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <glib.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34
35 #include "metadata/ctf-scanner.h"
36 #include "metadata/ctf-parser.h"
37 #include "metadata/ctf-ast.h"
38
39 /*
40 * We currently simply map a page to read the packet header and packet
41 * context to get the packet length and content length.
42 */
43 #define MAX_PACKET_HEADER_LEN getpagesize()
44 #define UUID_LEN 16 /* uuid by value len */
45
46 extern int yydebug;
47
48 struct trace_descriptor {
49 struct ctf_trace ctf_trace;
50 };
51
52 struct trace_descriptor *ctf_open_trace(const char *path, int flags);
53 void ctf_close_trace(struct trace_descriptor *descriptor);
54
55 static struct format ctf_format = {
56 .uint_read = ctf_uint_read,
57 .int_read = ctf_int_read,
58 .uint_write = ctf_uint_write,
59 .int_write = ctf_int_write,
60 .double_read = ctf_double_read,
61 .double_write = ctf_double_write,
62 .ldouble_read = ctf_ldouble_read,
63 .ldouble_write = ctf_ldouble_write,
64 .float_copy = ctf_float_copy,
65 .string_copy = ctf_string_copy,
66 .string_read = ctf_string_read,
67 .string_write = ctf_string_write,
68 .string_free_temp = ctf_string_free_temp,
69 .enum_read = ctf_enum_read,
70 .enum_write = ctf_enum_write,
71 .struct_begin = ctf_struct_begin,
72 .struct_end = ctf_struct_end,
73 .variant_begin = ctf_variant_begin,
74 .variant_end = ctf_variant_end,
75 .array_begin = ctf_array_begin,
76 .array_end = ctf_array_end,
77 .sequence_begin = ctf_sequence_begin,
78 .sequence_end = ctf_sequence_end,
79 .open_trace = ctf_open_trace,
80 .close_trace = ctf_close_trace,
81 };
82
83 void move_pos_slow(struct stream_pos *pos, size_t offset)
84 {
85 int ret;
86
87 /*
88 * The caller should never ask for move_pos across packets,
89 * except to get exactly at the beginning of the next packet.
90 */
91 assert(pos->offset + offset == pos->content_size);
92
93 if (pos->base) {
94 /* unmap old base */
95 ret = munmap(pos->base, pos->packet_size);
96 if (ret) {
97 fprintf(stdout, "Unable to unmap old base: %s.\n",
98 strerror(errno));
99 assert(0);
100 }
101 }
102
103 pos->mmap_offset += pos->packet_size / CHAR_BIT;
104 /* map new base. Need mapping length from header. */
105 pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN, PROT_READ,
106 MAP_PRIVATE, pos->fd, pos->mmap_offset);
107 pos->content_size = 0; /* Unknown at this point */
108 pos->packet_size = 0; /* Unknown at this point */
109
110 }
111
112 /*
113 * TODO: for now, we treat the metadata file as a simple text file
114 * (without any header nor packets nor padding).
115 */
116 static
117 int ctf_open_trace_metadata_read(struct trace_descriptor *td)
118 {
119 struct ctf_scanner *scanner;
120 FILE *fp;
121 int ret = 0;
122
123 td->ctf_trace.metadata.pos.fd = openat(td->ctf_trace.dirfd,
124 "metadata", O_RDONLY);
125 if (td->ctf_trace.metadata.pos.fd < 0) {
126 fprintf(stdout, "Unable to open metadata.\n");
127 return td->ctf_trace.metadata.pos.fd;
128 }
129
130 if (babeltrace_debug)
131 yydebug = 1;
132
133 fp = fdopen(td->ctf_trace.metadata.pos.fd, "r");
134 if (!fp) {
135 fprintf(stdout, "Unable to open metadata stream.\n");
136 ret = -errno;
137 goto end_stream;
138 }
139
140 scanner = ctf_scanner_alloc(fp);
141 if (!scanner) {
142 fprintf(stdout, "Error allocating scanner\n");
143 ret = -ENOMEM;
144 goto end_scanner_alloc;
145 }
146 ret = ctf_scanner_append_ast(scanner);
147 if (ret) {
148 fprintf(stdout, "Error creating AST\n");
149 goto end;
150 }
151
152 if (babeltrace_debug) {
153 ret = ctf_visitor_print_xml(stdout, 0, &scanner->ast->root);
154 if (ret) {
155 fprintf(stdout, "Error visiting AST for XML output\n");
156 goto end;
157 }
158 }
159
160 ret = ctf_visitor_semantic_check(stdout, 0, &scanner->ast->root);
161 if (ret) {
162 fprintf(stdout, "Error in CTF semantic validation %d\n", ret);
163 goto end;
164 }
165 ret = ctf_visitor_construct_metadata(stdout, 0, &scanner->ast->root,
166 &td->ctf_trace, BYTE_ORDER);
167 if (ret) {
168 fprintf(stdout, "Error in CTF metadata constructor %d\n", ret);
169 goto end;
170 }
171 end:
172 ctf_scanner_free(scanner);
173 end_scanner_alloc:
174 fclose(fp);
175 end_stream:
176 close(td->ctf_trace.metadata.pos.fd);
177 return ret;
178 }
179
180
181 static
182 int create_stream_packet_index(struct trace_descriptor *td,
183 struct ctf_file_stream *file_stream)
184 {
185 struct ctf_stream *stream;
186 int len_index;
187 struct stream_pos *pos;
188 struct stat filestats;
189 struct packet_index packet_index;
190 int first_packet = 1;
191 int ret;
192
193 pos = &file_stream->pos;
194
195 ret = fstat(pos->fd, &filestats);
196 if (ret < 0)
197 return ret;
198
199 for (pos->mmap_offset = 0; pos->mmap_offset < filestats.st_size; ) {
200 uint64_t stream_id = 0;
201
202 if (pos->base) {
203 /* unmap old base */
204 ret = munmap(pos->base, pos->packet_size);
205 if (ret) {
206 fprintf(stdout, "Unable to unmap old base: %s.\n",
207 strerror(errno));
208 return ret;
209 }
210 }
211 /* map new base. Need mapping length from header. */
212 pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN, PROT_READ,
213 MAP_PRIVATE, pos->fd, pos->mmap_offset);
214 pos->content_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
215 pos->packet_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
216 pos->offset = 0; /* Position of the packet header */
217
218 /* read and check header, set stream id (and check) */
219 if (td->ctf_trace.packet_header) {
220 /* Read packet header */
221 td->ctf_trace.packet_header->p.declaration->copy(NULL, NULL,
222 pos, &ctf_format, &td->ctf_trace.packet_header->p);
223
224 len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("magic"));
225 if (len_index >= 0) {
226 struct definition_integer *defint;
227 struct field *field;
228
229 field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
230 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
231 defint = container_of(field->definition, struct definition_integer, p);
232 assert(defint->declaration->signedness == FALSE);
233 if (defint->value._unsigned != CTF_MAGIC) {
234 fprintf(stdout, "[error] Invalid magic number %" PRIX64 ".\n",
235 defint->value._unsigned);
236 return -EINVAL;
237 }
238 }
239
240 /* check uuid */
241 len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("trace_uuid"));
242 if (len_index >= 0) {
243 struct definition_array *defarray;
244 struct field *field;
245 uint64_t i;
246 uint8_t uuidval[UUID_LEN];
247
248
249 field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
250 assert(field->definition->declaration->id == CTF_TYPE_ARRAY);
251 defarray = container_of(field->definition, struct definition_array, p);
252 assert(array_len(defarray) == UUID_LEN);
253 assert(defarray->declaration->elem->id == CTF_TYPE_INTEGER);
254
255 for (i = 0; i < UUID_LEN; i++) {
256 struct definition *elem;
257 struct definition_integer *defint;
258
259 elem = array_index(defarray, i);
260 assert(elem);
261 defint = container_of(elem, struct definition_integer, p);
262 uuidval[i] = defint->value._unsigned;
263 }
264 ret = uuid_compare(td->ctf_trace.uuid, uuidval);
265 if (ret) {
266 fprintf(stdout, "[error] Unique Universal Identifiers do not match.\n");
267 return -EINVAL;
268 }
269 }
270
271
272 len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("stream_id"));
273 if (len_index >= 0) {
274 struct definition_integer *defint;
275 struct field *field;
276
277 field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
278 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
279 defint = container_of(field->definition, struct definition_integer, p);
280 assert(defint->declaration->signedness == FALSE);
281 stream_id = defint->value._unsigned;
282 }
283 }
284
285 if (!first_packet && file_stream->stream_id != stream_id) {
286 fprintf(stdout, "[error] Stream ID is changing within a stream.\n");
287 return -EINVAL;
288 }
289 if (first_packet) {
290 file_stream->stream_id = stream_id;
291 if (stream_id >= td->ctf_trace.streams->len) {
292 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
293 return -EINVAL;
294 }
295 stream = g_ptr_array_index(td->ctf_trace.streams, stream_id);
296 if (!stream) {
297 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
298 return -EINVAL;
299 }
300 file_stream->stream = stream;
301 }
302 first_packet = 0;
303
304 if (stream->packet_context) {
305 /* Read packet context */
306 stream->packet_context->p.declaration->copy(NULL, NULL,
307 pos, &ctf_format, &stream->packet_context->p);
308
309 /* read content size from header */
310 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("content_size"));
311 if (len_index >= 0) {
312 struct definition_integer *defint;
313 struct field *field;
314
315 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
316 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
317 defint = container_of(field->definition, struct definition_integer, p);
318 assert(defint->declaration->signedness == FALSE);
319 pos->content_size = defint->value._unsigned;
320 } else {
321 /* Use file size for packet size */
322 pos->content_size = filestats.st_size * CHAR_BIT;
323 }
324
325 /* read packet size from header */
326 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("packet_size"));
327 if (len_index >= 0) {
328 struct definition_integer *defint;
329 struct field *field;
330
331 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
332 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
333 defint = container_of(field->definition, struct definition_integer, p);
334 assert(defint->declaration->signedness == FALSE);
335 pos->packet_size = defint->value._unsigned;
336 } else {
337 /* Use content size if non-zero, else file size */
338 pos->packet_size = pos->content_size ? : filestats.st_size * CHAR_BIT;
339 }
340 } else {
341 /* Use file size for packet size */
342 pos->content_size = filestats.st_size * CHAR_BIT;
343 /* Use content size if non-zero, else file size */
344 pos->packet_size = pos->content_size ? : filestats.st_size * CHAR_BIT;
345 }
346
347 packet_index.offset = pos->mmap_offset;
348 packet_index.content_size = pos->content_size;
349 packet_index.packet_size = pos->packet_size;
350 /* add index to packet array */
351 g_array_append_val(file_stream->pos.packet_index, packet_index);
352
353 pos->mmap_offset += pos->packet_size / CHAR_BIT;
354 }
355
356 return 0;
357 }
358
359 /*
360 * Note: many file streams can inherit from the same stream class
361 * description (metadata).
362 */
363 static
364 int ctf_open_file_stream_read(struct trace_descriptor *td, const char *path, int flags)
365 {
366 int ret;
367 struct ctf_file_stream *file_stream;
368
369 ret = openat(td->ctf_trace.dirfd, path, flags);
370 if (ret < 0)
371 goto error;
372 file_stream = g_new0(struct ctf_file_stream, 1);
373 file_stream->pos.fd = ret;
374 file_stream->pos.packet_index = g_array_new(FALSE, TRUE,
375 sizeof(struct packet_index));
376 ret = create_stream_packet_index(td, file_stream);
377 if (ret)
378 goto error_index;
379 /* Add stream file to stream class */
380 g_ptr_array_add(file_stream->stream->files, file_stream);
381 return 0;
382
383 error_index:
384 (void) g_array_free(file_stream->pos.packet_index, TRUE);
385 close(file_stream->pos.fd);
386 g_free(file_stream);
387 error:
388 return ret;
389 }
390
391 static
392 int ctf_open_trace_read(struct trace_descriptor *td, const char *path, int flags)
393 {
394 int ret;
395 struct dirent *dirent;
396 struct dirent *diriter;
397 size_t dirent_len;
398
399 td->ctf_trace.flags = flags;
400
401 /* Open trace directory */
402 td->ctf_trace.dir = opendir(path);
403 if (!td->ctf_trace.dir) {
404 fprintf(stdout, "[error] Unable to open trace directory.\n");
405 ret = -ENOENT;
406 goto error;
407 }
408
409 td->ctf_trace.dirfd = open(path, 0);
410 if (td->ctf_trace.dirfd < 0) {
411 fprintf(stdout, "[error] Unable to open trace directory file descriptor.\n");
412 ret = -ENOENT;
413 goto error_dirfd;
414 }
415
416 td->ctf_trace.streams = g_ptr_array_new();
417
418 /*
419 * Keep the metadata file separate.
420 */
421
422 ret = ctf_open_trace_metadata_read(td);
423 if (ret) {
424 goto error_metadata;
425 }
426
427 /*
428 * Open each stream: for each file, try to open, check magic
429 * number, and get the stream ID to add to the right location in
430 * the stream array.
431 */
432
433 dirent_len = offsetof(struct dirent, d_name) +
434 fpathconf(td->ctf_trace.dirfd, _PC_NAME_MAX) + 1;
435
436 dirent = malloc(dirent_len);
437
438 for (;;) {
439 ret = readdir_r(td->ctf_trace.dir, dirent, &diriter);
440 if (ret) {
441 fprintf(stdout, "[error] Readdir error.\n");
442 goto readdir_error;
443 }
444 if (!diriter)
445 break;
446 if (!strcmp(diriter->d_name, ".")
447 || !strcmp(diriter->d_name, "..")
448 || !strcmp(diriter->d_name, "metadata"))
449 continue;
450 ret = ctf_open_file_stream_read(td, diriter->d_name, flags);
451 if (ret) {
452 fprintf(stdout, "[error] Open file stream error.\n");
453 goto readdir_error;
454 }
455 }
456
457 free(dirent);
458 return 0;
459
460 readdir_error:
461 free(dirent);
462 error_metadata:
463 g_ptr_array_free(td->ctf_trace.streams, TRUE);
464 close(td->ctf_trace.dirfd);
465 error_dirfd:
466 closedir(td->ctf_trace.dir);
467 error:
468 return ret;
469 }
470
471 static
472 int ctf_open_trace_write(struct trace_descriptor *td, const char *path, int flags)
473 {
474 int ret;
475
476 ret = mkdir(path, S_IRWXU|S_IRWXG);
477 if (ret)
478 return ret;
479
480 /* Open trace directory */
481 td->ctf_trace.dir = opendir(path);
482 if (!td->ctf_trace.dir) {
483 fprintf(stdout, "Unable to open trace directory.\n");
484 ret = -ENOENT;
485 goto error;
486 }
487
488
489 return 0;
490
491 error:
492 return ret;
493 }
494
495 struct trace_descriptor *ctf_open_trace(const char *path, int flags)
496 {
497 struct trace_descriptor *td;
498 int ret;
499
500 td = g_new0(struct trace_descriptor, 1);
501
502 switch (flags) {
503 case O_RDONLY:
504 ret = ctf_open_trace_read(td, path, flags);
505 if (ret)
506 goto error;
507 break;
508 case O_WRONLY:
509 ret = ctf_open_trace_write(td, path, flags);
510 if (ret)
511 goto error;
512 break;
513 default:
514 fprintf(stdout, "Incorrect open flags.\n");
515 goto error;
516 }
517
518 return td;
519 error:
520 g_free(td);
521 return NULL;
522 }
523
524 static
525 void ctf_close_file_stream(struct ctf_file_stream *file_stream)
526 {
527 (void) g_array_free(file_stream->pos.packet_index, TRUE);
528 close(file_stream->pos.fd);
529 }
530
531 void ctf_close_trace(struct trace_descriptor *td)
532 {
533 int i;
534
535 if (td->ctf_trace.streams) {
536 for (i = 0; i < td->ctf_trace.streams->len; i++) {
537 struct ctf_stream *stream;
538 int j;
539
540 stream = g_ptr_array_index(td->ctf_trace.streams, i);
541 for (j = 0; j < stream->files->len; j++) {
542 struct ctf_file_stream *file_stream;
543 file_stream = g_ptr_array_index(td->ctf_trace.streams, j);
544 ctf_close_file_stream(file_stream);
545 }
546
547 }
548 g_ptr_array_free(td->ctf_trace.streams, TRUE);
549 }
550 closedir(td->ctf_trace.dir);
551 g_free(td);
552 }
553
554 void __attribute__((constructor)) ctf_init(void)
555 {
556 int ret;
557
558 ctf_format.name = g_quark_from_static_string("ctf");
559 ret = bt_register_format(&ctf_format);
560 assert(!ret);
561 }
562
563 /* TODO: finalize */
This page took 0.039784 seconds and 4 git commands to generate.