Don't ever support named struct, enum, variant declaration within structures
[babeltrace.git] / formats / ctf / ctf.c
CommitLineData
fc93b2bd
MD
1/*
2 * BabelTrace - Common Trace Format (CTF)
3 *
4 * Format registration.
5 *
c054553d 6 * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
fc93b2bd 7 *
ccd7e1c8
MD
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:
fc93b2bd 14 *
ccd7e1c8
MD
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
fc93b2bd
MD
17 */
18
19#include <babeltrace/format.h>
20#include <babeltrace/ctf/types.h>
bbefb8dd 21#include <babeltrace/ctf/metadata.h>
65102a8c 22#include <babeltrace/babeltrace.h>
0f980a35
MD
23#include <inttypes.h>
24#include <uuid/uuid.h>
25#include <sys/mman.h>
bbefb8dd 26#include <errno.h>
bbefb8dd 27#include <sys/types.h>
65102a8c 28#include <sys/stat.h>
bbefb8dd 29#include <fcntl.h>
65102a8c 30#include <dirent.h>
bbefb8dd 31#include <glib.h>
65102a8c
MD
32#include <unistd.h>
33#include <stdlib.h>
34
65102a8c
MD
35#include "metadata/ctf-scanner.h"
36#include "metadata/ctf-parser.h"
37#include "metadata/ctf-ast.h"
38
0f980a35
MD
39/*
40 * We currently simply map a page to read the packet header and packet
8c572eba 41 * context to get the packet length and content length. (in bits)
0f980a35 42 */
8c572eba
MD
43#define MAX_PACKET_HEADER_LEN (getpagesize() * CHAR_BIT)
44#define WRITE_PACKET_LEN (getpagesize() * 8 * CHAR_BIT)
0f980a35
MD
45#define UUID_LEN 16 /* uuid by value len */
46
65102a8c 47extern int yydebug;
bbefb8dd 48
bbefb8dd
MD
49struct trace_descriptor *ctf_open_trace(const char *path, int flags);
50void ctf_close_trace(struct trace_descriptor *descriptor);
fc93b2bd 51
1ae19169
MD
52static
53rw_dispatch read_dispatch_table[] = {
d11e9c49
MD
54 [ CTF_TYPE_INTEGER ] = ctf_integer_read,
55 [ CTF_TYPE_FLOAT ] = ctf_float_read,
56 [ CTF_TYPE_ENUM ] = ctf_enum_read,
57 [ CTF_TYPE_STRING ] = ctf_string_read,
58 [ CTF_TYPE_STRUCT ] = ctf_struct_rw,
59 [ CTF_TYPE_VARIANT ] = ctf_variant_rw,
60 [ CTF_TYPE_ARRAY ] = ctf_array_rw,
61 [ CTF_TYPE_SEQUENCE ] = ctf_sequence_rw,
62};
63
1ae19169
MD
64static
65rw_dispatch write_dispatch_table[] = {
d11e9c49
MD
66 [ CTF_TYPE_INTEGER ] = ctf_integer_write,
67 [ CTF_TYPE_FLOAT ] = ctf_float_write,
68 [ CTF_TYPE_ENUM ] = ctf_enum_write,
69 [ CTF_TYPE_STRING ] = ctf_string_write,
70 [ CTF_TYPE_STRUCT ] = ctf_struct_rw,
71 [ CTF_TYPE_VARIANT ] = ctf_variant_rw,
72 [ CTF_TYPE_ARRAY ] = ctf_array_rw,
73 [ CTF_TYPE_SEQUENCE ] = ctf_sequence_rw,
74};
75
1ae19169 76static
d11e9c49 77struct format ctf_format = {
bbefb8dd
MD
78 .open_trace = ctf_open_trace,
79 .close_trace = ctf_close_trace,
fc93b2bd
MD
80};
81
31262354 82static
764af3f4 83int ctf_read_event(struct stream_pos *ppos, struct ctf_stream *stream)
31262354
MD
84{
85 struct ctf_stream_pos *pos =
86 container_of(ppos, struct ctf_stream_pos, parent);
764af3f4 87 struct ctf_stream_class *stream_class = stream->stream_class;
31262354
MD
88 struct ctf_event *event_class;
89 uint64_t id = 0;
90 int len_index;
91 int ret;
92
93 if (pos->offset == EOF)
94 return EOF;
95
96 /* Read event header */
97 if (stream_class->event_header) {
98 ret = generic_rw(ppos, &stream_class->event_header->p);
99 if (ret)
100 goto error;
101 /* lookup event id */
102 len_index = struct_declaration_lookup_field_index(stream_class->event_header_decl,
103 g_quark_from_static_string("id"));
104 if (len_index >= 0) {
105 struct definition_integer *defint;
106 struct definition *field;
107
108 field = struct_definition_get_field_from_index(stream_class->event_header, len_index);
109 assert(field->declaration->id == CTF_TYPE_INTEGER);
110 defint = container_of(field, struct definition_integer, p);
111 assert(defint->declaration->signedness == FALSE);
112 id = defint->value._unsigned; /* set id */
113 }
764af3f4
MD
114
115 /* lookup timestamp */
116 len_index = struct_declaration_lookup_field_index(stream_class->event_header_decl,
117 g_quark_from_static_string("timestamp"));
118 if (len_index >= 0) {
119 struct definition_integer *defint;
120 struct definition *field;
121
122 field = struct_definition_get_field_from_index(stream_class->event_header, len_index);
123 assert(field->declaration->id == CTF_TYPE_INTEGER);
124 defint = container_of(field, struct definition_integer, p);
125 assert(defint->declaration->signedness == FALSE);
126 /* update timestamp */
127 stream->timestamp = defint->value._unsigned;
128 }
129
31262354
MD
130 }
131
132 /* Read stream-declared event context */
133 if (stream_class->event_context) {
134 ret = generic_rw(ppos, &stream_class->event_context->p);
135 if (ret)
136 goto error;
137 }
138
139 if (id >= stream_class->events_by_id->len) {
140 fprintf(stdout, "[error] Event id %" PRIu64 " is outside range.\n", id);
141 return -EINVAL;
142 }
143 event_class = g_ptr_array_index(stream_class->events_by_id, id);
144 if (!event_class) {
145 fprintf(stdout, "[error] Event id %" PRIu64 " is unknown.\n", id);
146 return -EINVAL;
147 }
148
149 /* Read event-declared event context */
150 if (event_class->context) {
151 ret = generic_rw(ppos, &event_class->context->p);
152 if (ret)
153 goto error;
154 }
155
156 /* Read event payload */
157 if (event_class->fields) {
158 ret = generic_rw(ppos, &event_class->fields->p);
159 if (ret)
160 goto error;
161 }
162
163 return 0;
164
165error:
166 fprintf(stdout, "[error] Unexpected end of stream. Either the trace data stream is corrupted or metadata description does not match data layout.\n");
167 return ret;
168}
169
170static
764af3f4 171int ctf_write_event(struct stream_pos *pos, struct ctf_stream *stream)
31262354 172{
764af3f4 173 struct ctf_stream_class *stream_class = stream->stream_class;
31262354
MD
174 struct ctf_event *event_class;
175 uint64_t id = 0;
176 int len_index;
177 int ret;
178
179 /* print event header */
180 if (stream_class->event_header) {
181 /* lookup event id */
182 len_index = struct_declaration_lookup_field_index(stream_class->event_header_decl,
183 g_quark_from_static_string("id"));
184 if (len_index >= 0) {
185 struct definition_integer *defint;
186 struct definition *field;
187
188 field = struct_definition_get_field_from_index(stream_class->event_header, len_index);
189 assert(field->declaration->id == CTF_TYPE_INTEGER);
190 defint = container_of(field, struct definition_integer, p);
191 assert(defint->declaration->signedness == FALSE);
192 id = defint->value._unsigned; /* set id */
193 }
194
195 ret = generic_rw(pos, &stream_class->event_header->p);
196 if (ret)
197 goto error;
198 }
199
200 /* print stream-declared event context */
201 if (stream_class->event_context) {
202 ret = generic_rw(pos, &stream_class->event_context->p);
203 if (ret)
204 goto error;
205 }
206
207 if (id >= stream_class->events_by_id->len) {
208 fprintf(stdout, "[error] Event id %" PRIu64 " is outside range.\n", id);
209 return -EINVAL;
210 }
211 event_class = g_ptr_array_index(stream_class->events_by_id, id);
212 if (!event_class) {
213 fprintf(stdout, "[error] Event id %" PRIu64 " is unknown.\n", id);
214 return -EINVAL;
215 }
216
217 /* print event-declared event context */
218 if (event_class->context) {
219 ret = generic_rw(pos, &event_class->context->p);
220 if (ret)
221 goto error;
222 }
223
224 /* Read and print event payload */
225 if (event_class->fields) {
226 ret = generic_rw(pos, &event_class->fields->p);
227 if (ret)
228 goto error;
229 }
230
231 return 0;
232
233error:
234 fprintf(stdout, "[error] Unexpected end of stream. Either the trace data stream is corrupted or metadata description does not match data layout.\n");
235 return ret;
236}
237
8563e754 238void ctf_init_pos(struct ctf_stream_pos *pos, int fd, int open_flags)
8c572eba
MD
239{
240 pos->fd = fd;
241 pos->mmap_offset = 0;
242 pos->packet_size = 0;
243 pos->content_size = 0;
244 pos->content_size_loc = NULL;
245 pos->base = NULL;
246 pos->offset = 0;
247 pos->dummy = false;
8c572eba 248 pos->cur_index = 0;
8563e754
MD
249 if (fd >= 0)
250 pos->packet_index = g_array_new(FALSE, TRUE,
251 sizeof(struct packet_index));
252 else
253 pos->packet_index = NULL;
8563e754
MD
254 switch (open_flags & O_ACCMODE) {
255 case O_RDONLY:
256 pos->prot = PROT_READ;
257 pos->flags = MAP_PRIVATE;
258 pos->parent.rw_table = read_dispatch_table;
31262354 259 pos->parent.event_cb = ctf_read_event;
8563e754 260 break;
8563e754
MD
261 case O_RDWR:
262 pos->prot = PROT_WRITE; /* Write has priority */
263 pos->flags = MAP_SHARED;
264 pos->parent.rw_table = write_dispatch_table;
31262354 265 pos->parent.event_cb = ctf_write_event;
8563e754 266 if (fd >= 0)
847bf71a 267 ctf_move_pos_slow(pos, 0, SEEK_SET); /* position for write */
8563e754
MD
268 break;
269 default:
270 assert(0);
8c572eba
MD
271 }
272}
273
46322b33 274void ctf_fini_pos(struct ctf_stream_pos *pos)
8c572eba
MD
275{
276 int ret;
277
278 if (pos->prot == PROT_WRITE && pos->content_size_loc)
279 *pos->content_size_loc = pos->offset;
280 if (pos->base) {
281 /* unmap old base */
282 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
283 if (ret) {
46322b33 284 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
8c572eba
MD
285 strerror(errno));
286 assert(0);
287 }
288 }
289 (void) g_array_free(pos->packet_index, TRUE);
290}
291
847bf71a 292void ctf_move_pos_slow(struct ctf_stream_pos *pos, size_t offset, int whence)
0f980a35
MD
293{
294 int ret;
8c572eba
MD
295 off_t off;
296 struct packet_index *index;
0f980a35 297
8c572eba
MD
298 if (pos->prot == PROT_WRITE && pos->content_size_loc)
299 *pos->content_size_loc = pos->offset;
0f980a35
MD
300
301 if (pos->base) {
302 /* unmap old base */
8c572eba 303 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
0f980a35 304 if (ret) {
46322b33 305 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
0f980a35
MD
306 strerror(errno));
307 assert(0);
308 }
847bf71a 309 pos->base = NULL;
0f980a35
MD
310 }
311
8c572eba 312 /*
46322b33 313 * The caller should never ask for ctf_move_pos across packets,
8c572eba
MD
314 * except to get exactly at the beginning of the next packet.
315 */
316 if (pos->prot == PROT_WRITE) {
989c73bc
MD
317 switch (whence) {
318 case SEEK_CUR:
319 /* The writer will add padding */
320 assert(pos->offset + offset == pos->packet_size);
8c572eba 321 pos->mmap_offset += WRITE_PACKET_LEN / CHAR_BIT;
989c73bc
MD
322 break;
323 case SEEK_SET:
324 assert(offset == 0); /* only seek supported for now */
325 pos->cur_index = 0;
326 break;
327 default:
328 assert(0);
329 }
8c572eba
MD
330 pos->content_size = -1U; /* Unknown at this point */
331 pos->packet_size = WRITE_PACKET_LEN;
989c73bc
MD
332 off = posix_fallocate(pos->fd, pos->mmap_offset,
333 pos->packet_size / CHAR_BIT);
8c572eba 334 assert(off >= 0);
847bf71a 335 pos->offset = 0;
8c572eba 336 } else {
847bf71a
MD
337 switch (whence) {
338 case SEEK_CUR:
339 /* The reader will expect us to skip padding */
340 assert(pos->offset + offset == pos->content_size);
8c572eba 341 ++pos->cur_index;
847bf71a
MD
342 break;
343 case SEEK_SET:
344 assert(offset == 0); /* only seek supported for now */
345 pos->cur_index = 0;
346 break;
347 default:
348 assert(0);
349 }
350 if (pos->cur_index >= pos->packet_index->len) {
670977d3 351 pos->offset = EOF;
847bf71a
MD
352 return;
353 }
8c572eba
MD
354 index = &g_array_index(pos->packet_index, struct packet_index,
355 pos->cur_index);
356 pos->mmap_offset = index->offset;
357
358 /* Lookup context/packet size in index */
359 pos->content_size = index->content_size;
360 pos->packet_size = index->packet_size;
847bf71a 361 pos->offset = index->data_offset;
8c572eba 362 }
0f980a35 363 /* map new base. Need mapping length from header. */
8c572eba
MD
364 pos->base = mmap(NULL, pos->packet_size / CHAR_BIT, pos->prot,
365 pos->flags, pos->fd, pos->mmap_offset);
847bf71a
MD
366 if (pos->base == MAP_FAILED) {
367 fprintf(stdout, "[error] mmap error %s.\n",
368 strerror(errno));
369 assert(0);
370 }
0f980a35
MD
371}
372
65102a8c
MD
373/*
374 * TODO: for now, we treat the metadata file as a simple text file
375 * (without any header nor packets nor padding).
376 */
377static
46322b33 378int ctf_open_trace_metadata_read(struct ctf_trace *td)
65102a8c
MD
379{
380 struct ctf_scanner *scanner;
381 FILE *fp;
382 int ret = 0;
383
46322b33
MD
384 td->metadata.pos.fd = openat(td->dirfd, "metadata", O_RDONLY);
385 if (td->metadata.pos.fd < 0) {
65102a8c 386 fprintf(stdout, "Unable to open metadata.\n");
46322b33 387 return td->metadata.pos.fd;
65102a8c
MD
388 }
389
390 if (babeltrace_debug)
391 yydebug = 1;
392
46322b33 393 fp = fdopen(td->metadata.pos.fd, "r");
65102a8c 394 if (!fp) {
46322b33 395 fprintf(stdout, "[error] Unable to open metadata stream.\n");
65102a8c
MD
396 ret = -errno;
397 goto end_stream;
398 }
399
400 scanner = ctf_scanner_alloc(fp);
401 if (!scanner) {
46322b33 402 fprintf(stdout, "[error] Error allocating scanner\n");
65102a8c
MD
403 ret = -ENOMEM;
404 goto end_scanner_alloc;
405 }
406 ret = ctf_scanner_append_ast(scanner);
407 if (ret) {
46322b33 408 fprintf(stdout, "[error] Error creating AST\n");
65102a8c
MD
409 goto end;
410 }
411
412 if (babeltrace_debug) {
413 ret = ctf_visitor_print_xml(stdout, 0, &scanner->ast->root);
414 if (ret) {
46322b33 415 fprintf(stdout, "[error] Error visiting AST for XML output\n");
65102a8c
MD
416 goto end;
417 }
418 }
419
420 ret = ctf_visitor_semantic_check(stdout, 0, &scanner->ast->root);
421 if (ret) {
46322b33 422 fprintf(stdout, "[error] Error in CTF semantic validation %d\n", ret);
65102a8c
MD
423 goto end;
424 }
425 ret = ctf_visitor_construct_metadata(stdout, 0, &scanner->ast->root,
46322b33 426 td, BYTE_ORDER);
65102a8c 427 if (ret) {
46322b33 428 fprintf(stdout, "[error] Error in CTF metadata constructor %d\n", ret);
65102a8c
MD
429 goto end;
430 }
431end:
432 ctf_scanner_free(scanner);
433end_scanner_alloc:
434 fclose(fp);
435end_stream:
46322b33 436 close(td->metadata.pos.fd);
0f980a35
MD
437 return ret;
438}
439
440
441static
46322b33 442int create_stream_packet_index(struct ctf_trace *td,
0f980a35
MD
443 struct ctf_file_stream *file_stream)
444{
aa6bffae 445 struct ctf_stream_class *stream;
0f980a35 446 int len_index;
46322b33 447 struct ctf_stream_pos *pos;
0f980a35
MD
448 struct stat filestats;
449 struct packet_index packet_index;
450 int first_packet = 1;
451 int ret;
452
453 pos = &file_stream->pos;
454
455 ret = fstat(pos->fd, &filestats);
456 if (ret < 0)
457 return ret;
458
459 for (pos->mmap_offset = 0; pos->mmap_offset < filestats.st_size; ) {
460 uint64_t stream_id = 0;
461
462 if (pos->base) {
463 /* unmap old base */
8c572eba 464 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
0f980a35 465 if (ret) {
46322b33 466 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
0f980a35
MD
467 strerror(errno));
468 return ret;
469 }
8c572eba 470 pos->base = NULL;
0f980a35
MD
471 }
472 /* map new base. Need mapping length from header. */
8c572eba 473 pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN / CHAR_BIT, PROT_READ,
0f980a35 474 MAP_PRIVATE, pos->fd, pos->mmap_offset);
dc48ecad
MD
475 pos->content_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
476 pos->packet_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
0f980a35
MD
477 pos->offset = 0; /* Position of the packet header */
478
8c572eba
MD
479 packet_index.offset = pos->mmap_offset;
480 packet_index.content_size = 0;
481 packet_index.packet_size = 0;
482
0f980a35 483 /* read and check header, set stream id (and check) */
46322b33 484 if (td->packet_header) {
0f980a35 485 /* Read packet header */
c5e74408
MD
486 ret = generic_rw(&pos->parent, &td->packet_header->p);
487 if (ret)
488 return ret;
46322b33 489 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("magic"));
0f980a35
MD
490 if (len_index >= 0) {
491 struct definition_integer *defint;
b1a2f580 492 struct definition *field;
0f980a35 493
46322b33 494 field = struct_definition_get_field_from_index(td->packet_header, len_index);
b1a2f580
MD
495 assert(field->declaration->id == CTF_TYPE_INTEGER);
496 defint = container_of(field, struct definition_integer, p);
0f980a35
MD
497 assert(defint->declaration->signedness == FALSE);
498 if (defint->value._unsigned != CTF_MAGIC) {
d8ea2d29 499 fprintf(stdout, "[error] Invalid magic number 0x%" PRIX64 " at packet %u (file offset %zd).\n",
8c572eba
MD
500 defint->value._unsigned,
501 file_stream->pos.packet_index->len,
502 (ssize_t) pos->mmap_offset);
0f980a35
MD
503 return -EINVAL;
504 }
505 }
506
507 /* check uuid */
46322b33 508 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("trace_uuid"));
0f980a35
MD
509 if (len_index >= 0) {
510 struct definition_array *defarray;
b1a2f580 511 struct definition *field;
0f980a35
MD
512 uint64_t i;
513 uint8_t uuidval[UUID_LEN];
514
46322b33 515 field = struct_definition_get_field_from_index(td->packet_header, len_index);
b1a2f580
MD
516 assert(field->declaration->id == CTF_TYPE_ARRAY);
517 defarray = container_of(field, struct definition_array, p);
3838df27 518 assert(array_len(defarray) == UUID_LEN);
0f980a35
MD
519 assert(defarray->declaration->elem->id == CTF_TYPE_INTEGER);
520
521 for (i = 0; i < UUID_LEN; i++) {
522 struct definition *elem;
523 struct definition_integer *defint;
524
525 elem = array_index(defarray, i);
526 assert(elem);
527 defint = container_of(elem, struct definition_integer, p);
528 uuidval[i] = defint->value._unsigned;
529 }
46322b33 530 ret = uuid_compare(td->uuid, uuidval);
0f980a35
MD
531 if (ret) {
532 fprintf(stdout, "[error] Unique Universal Identifiers do not match.\n");
533 return -EINVAL;
534 }
535 }
536
537
46322b33 538 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("stream_id"));
0f980a35
MD
539 if (len_index >= 0) {
540 struct definition_integer *defint;
b1a2f580 541 struct definition *field;
0f980a35 542
46322b33 543 field = struct_definition_get_field_from_index(td->packet_header, len_index);
b1a2f580
MD
544 assert(field->declaration->id == CTF_TYPE_INTEGER);
545 defint = container_of(field, struct definition_integer, p);
0f980a35
MD
546 assert(defint->declaration->signedness == FALSE);
547 stream_id = defint->value._unsigned;
548 }
549 }
550
551 if (!first_packet && file_stream->stream_id != stream_id) {
552 fprintf(stdout, "[error] Stream ID is changing within a stream.\n");
553 return -EINVAL;
554 }
555 if (first_packet) {
556 file_stream->stream_id = stream_id;
46322b33 557 if (stream_id >= td->streams->len) {
0f980a35
MD
558 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
559 return -EINVAL;
560 }
46322b33 561 stream = g_ptr_array_index(td->streams, stream_id);
0f980a35
MD
562 if (!stream) {
563 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
564 return -EINVAL;
565 }
764af3f4 566 file_stream->stream.stream_class = stream;
0f980a35
MD
567 }
568 first_packet = 0;
569
dc48ecad
MD
570 if (stream->packet_context) {
571 /* Read packet context */
c5e74408
MD
572 ret = generic_rw(&pos->parent, &stream->packet_context->p);
573 if (ret)
574 return ret;
dc48ecad
MD
575 /* read content size from header */
576 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("content_size"));
577 if (len_index >= 0) {
578 struct definition_integer *defint;
b1a2f580 579 struct definition *field;
dc48ecad
MD
580
581 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
b1a2f580
MD
582 assert(field->declaration->id == CTF_TYPE_INTEGER);
583 defint = container_of(field, struct definition_integer, p);
dc48ecad 584 assert(defint->declaration->signedness == FALSE);
8c572eba 585 packet_index.content_size = defint->value._unsigned;
dc48ecad
MD
586 } else {
587 /* Use file size for packet size */
8c572eba 588 packet_index.content_size = filestats.st_size * CHAR_BIT;
dc48ecad
MD
589 }
590
591 /* read packet size from header */
592 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("packet_size"));
593 if (len_index >= 0) {
594 struct definition_integer *defint;
b1a2f580 595 struct definition *field;
dc48ecad
MD
596
597 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
b1a2f580
MD
598 assert(field->declaration->id == CTF_TYPE_INTEGER);
599 defint = container_of(field, struct definition_integer, p);
dc48ecad 600 assert(defint->declaration->signedness == FALSE);
8c572eba 601 packet_index.packet_size = defint->value._unsigned;
dc48ecad
MD
602 } else {
603 /* Use content size if non-zero, else file size */
8c572eba 604 packet_index.packet_size = packet_index.content_size ? : filestats.st_size * CHAR_BIT;
dc48ecad 605 }
0f980a35
MD
606 } else {
607 /* Use file size for packet size */
8c572eba 608 packet_index.content_size = filestats.st_size * CHAR_BIT;
0f980a35 609 /* Use content size if non-zero, else file size */
8c572eba 610 packet_index.packet_size = packet_index.content_size ? : filestats.st_size * CHAR_BIT;
0f980a35 611 }
546293fa
MD
612
613 /* Validate content size and packet size values */
614 if (packet_index.content_size > packet_index.packet_size) {
615 fprintf(stdout, "[error] Content size (%zu bits) is larger than packet size (%zu bits).\n",
616 packet_index.content_size, packet_index.packet_size);
617 return -EINVAL;
618 }
619
58b0b883
MD
620 if (packet_index.packet_size > (filestats.st_size - packet_index.offset) * CHAR_BIT) {
621 fprintf(stdout, "[error] Packet size (%zu bits) is larger than remaining file size (%zu bits).\n",
622 packet_index.content_size, (filestats.st_size - packet_index.offset) * CHAR_BIT);
546293fa
MD
623 return -EINVAL;
624 }
625
847bf71a
MD
626 /* Save position after header and context */
627 packet_index.data_offset = pos->offset;
0f980a35 628
0f980a35
MD
629 /* add index to packet array */
630 g_array_append_val(file_stream->pos.packet_index, packet_index);
631
8c572eba 632 pos->mmap_offset += packet_index.packet_size / CHAR_BIT;
0f980a35
MD
633 }
634
847bf71a
MD
635 /* Move pos back to beginning of file */
636 ctf_move_pos_slow(pos, 0, SEEK_SET); /* position for write */
637
0f980a35
MD
638 return 0;
639}
640
641/*
642 * Note: many file streams can inherit from the same stream class
643 * description (metadata).
644 */
645static
46322b33 646int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags)
0f980a35
MD
647{
648 int ret;
649 struct ctf_file_stream *file_stream;
650
46322b33 651 ret = openat(td->dirfd, path, flags);
0f980a35
MD
652 if (ret < 0)
653 goto error;
654 file_stream = g_new0(struct ctf_file_stream, 1);
8563e754 655 ctf_init_pos(&file_stream->pos, ret, flags);
0f980a35
MD
656 ret = create_stream_packet_index(td, file_stream);
657 if (ret)
658 goto error_index;
659 /* Add stream file to stream class */
764af3f4 660 g_ptr_array_add(file_stream->stream.stream_class->files, file_stream);
0f980a35
MD
661 return 0;
662
663error_index:
46322b33 664 ctf_fini_pos(&file_stream->pos);
0f980a35
MD
665 close(file_stream->pos.fd);
666 g_free(file_stream);
667error:
65102a8c
MD
668 return ret;
669}
670
bbefb8dd 671static
46322b33 672int ctf_open_trace_read(struct ctf_trace *td, const char *path, int flags)
bbefb8dd
MD
673{
674 int ret;
65102a8c
MD
675 struct dirent *dirent;
676 struct dirent *diriter;
677 size_t dirent_len;
bbefb8dd 678
46322b33 679 td->flags = flags;
bbefb8dd
MD
680
681 /* Open trace directory */
46322b33
MD
682 td->dir = opendir(path);
683 if (!td->dir) {
dc48ecad 684 fprintf(stdout, "[error] Unable to open trace directory.\n");
bbefb8dd
MD
685 ret = -ENOENT;
686 goto error;
687 }
688
46322b33
MD
689 td->dirfd = open(path, 0);
690 if (td->dirfd < 0) {
dc48ecad 691 fprintf(stdout, "[error] Unable to open trace directory file descriptor.\n");
65102a8c
MD
692 ret = -ENOENT;
693 goto error_dirfd;
694 }
0f980a35 695
65102a8c
MD
696 /*
697 * Keep the metadata file separate.
698 */
bbefb8dd 699
65102a8c
MD
700 ret = ctf_open_trace_metadata_read(td);
701 if (ret) {
702 goto error_metadata;
703 }
bbefb8dd
MD
704
705 /*
706 * Open each stream: for each file, try to open, check magic
707 * number, and get the stream ID to add to the right location in
708 * the stream array.
bbefb8dd
MD
709 */
710
65102a8c 711 dirent_len = offsetof(struct dirent, d_name) +
46322b33 712 fpathconf(td->dirfd, _PC_NAME_MAX) + 1;
bbefb8dd 713
65102a8c 714 dirent = malloc(dirent_len);
bbefb8dd 715
65102a8c 716 for (;;) {
46322b33 717 ret = readdir_r(td->dir, dirent, &diriter);
65102a8c 718 if (ret) {
dc48ecad 719 fprintf(stdout, "[error] Readdir error.\n");
65102a8c 720 goto readdir_error;
65102a8c
MD
721 }
722 if (!diriter)
723 break;
d8ea2d29
MD
724 /* Ignore hidden files, ., .. and metadata. */
725 if (!strncmp(diriter->d_name, ".", 1)
65102a8c
MD
726 || !strcmp(diriter->d_name, "..")
727 || !strcmp(diriter->d_name, "metadata"))
728 continue;
dc48ecad
MD
729 ret = ctf_open_file_stream_read(td, diriter->d_name, flags);
730 if (ret) {
731 fprintf(stdout, "[error] Open file stream error.\n");
732 goto readdir_error;
733 }
65102a8c 734 }
bbefb8dd 735
65102a8c 736 free(dirent);
bbefb8dd 737 return 0;
65102a8c
MD
738
739readdir_error:
740 free(dirent);
741error_metadata:
46322b33
MD
742 g_ptr_array_free(td->streams, TRUE);
743 close(td->dirfd);
65102a8c 744error_dirfd:
46322b33 745 closedir(td->dir);
bbefb8dd
MD
746error:
747 return ret;
748}
749
bbefb8dd
MD
750struct trace_descriptor *ctf_open_trace(const char *path, int flags)
751{
46322b33 752 struct ctf_trace *td;
bbefb8dd
MD
753 int ret;
754
46322b33 755 td = g_new0(struct ctf_trace, 1);
bbefb8dd 756
8c572eba 757 switch (flags & O_ACCMODE) {
bbefb8dd 758 case O_RDONLY:
b61922b5
MD
759 if (!path) {
760 fprintf(stdout, "[error] Path missing for input CTF trace.\n");
761 goto error;
762 }
bbefb8dd
MD
763 ret = ctf_open_trace_read(td, path, flags);
764 if (ret)
765 goto error;
766 break;
989c73bc 767 case O_RDWR:
46322b33
MD
768 fprintf(stdout, "[error] Opening CTF traces for output is not supported yet.\n");
769 goto error;
bbefb8dd 770 default:
46322b33 771 fprintf(stdout, "[error] Incorrect open flags.\n");
bbefb8dd
MD
772 goto error;
773 }
774
46322b33 775 return &td->parent;
bbefb8dd
MD
776error:
777 g_free(td);
778 return NULL;
779}
780
0f980a35
MD
781static
782void ctf_close_file_stream(struct ctf_file_stream *file_stream)
783{
46322b33 784 ctf_fini_pos(&file_stream->pos);
0f980a35
MD
785 close(file_stream->pos.fd);
786}
787
46322b33 788void ctf_close_trace(struct trace_descriptor *tdp)
bbefb8dd 789{
46322b33 790 struct ctf_trace *td = container_of(tdp, struct ctf_trace, parent);
0f980a35
MD
791 int i;
792
46322b33
MD
793 if (td->streams) {
794 for (i = 0; i < td->streams->len; i++) {
aa6bffae 795 struct ctf_stream_class *stream;
0f980a35 796 int j;
46322b33 797 stream = g_ptr_array_index(td->streams, i);
0f980a35
MD
798 for (j = 0; j < stream->files->len; j++) {
799 struct ctf_file_stream *file_stream;
2c117823 800 file_stream = g_ptr_array_index(stream->files, j);
0f980a35
MD
801 ctf_close_file_stream(file_stream);
802 }
803
804 }
46322b33 805 g_ptr_array_free(td->streams, TRUE);
0f980a35 806 }
46322b33 807 closedir(td->dir);
bbefb8dd
MD
808 g_free(td);
809}
810
7fb21036 811void __attribute__((constructor)) ctf_init(void)
fc93b2bd
MD
812{
813 int ret;
814
4c8bfb7e 815 ctf_format.name = g_quark_from_static_string("ctf");
fc93b2bd
MD
816 ret = bt_register_format(&ctf_format);
817 assert(!ret);
818}
698f0fe4
MD
819
820/* TODO: finalize */
This page took 0.063175 seconds and 4 git commands to generate.