7407ad339dbf927bce3f741f29e61ac6782a8a64
[babeltrace.git] / src / plugins / ctf / common / metadata / decoder.c
1 /*
2 * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 */
14
15 #define BT_COMP_LOG_SELF_COMP (mdec->config.self_comp)
16 #define BT_LOG_OUTPUT_LEVEL (mdec->config.log_level)
17 #define BT_LOG_TAG "PLUGIN/CTF/META/DECODER"
18 #include "logging/comp-logging.h"
19
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <inttypes.h>
25 #include "common/assert.h"
26 #include "common/uuid.h"
27 #include "compat/memstream.h"
28 #include <babeltrace2/babeltrace.h>
29 #include <glib.h>
30 #include <string.h>
31
32 #include "ast.h"
33 #include "decoder.h"
34 #include "scanner.h"
35 #include "logging.h"
36
37 #define TSDL_MAGIC 0x75d11d57
38
39 extern
40 int yydebug;
41
42 struct ctf_metadata_decoder {
43 struct ctf_scanner *scanner;
44 GString *text;
45 struct ctf_visitor_generate_ir *visitor;
46 bt_uuid_t uuid;
47 bool is_uuid_set;
48 int bo;
49 struct ctf_metadata_decoder_config config;
50 struct meta_log_config log_cfg;
51 };
52
53 struct packet_header {
54 uint32_t magic;
55 bt_uuid_t uuid;
56 uint32_t checksum;
57 uint32_t content_size;
58 uint32_t packet_size;
59 uint8_t compression_scheme;
60 uint8_t encryption_scheme;
61 uint8_t checksum_scheme;
62 uint8_t major;
63 uint8_t minor;
64 } __attribute__((__packed__));
65
66 BT_HIDDEN
67 int ctf_metadata_decoder_packetized_file_stream_to_buf(FILE *fp,
68 char **buf, int byte_order, bool *is_uuid_set,
69 uint8_t *uuid, bt_logging_level log_level,
70 bt_self_component *self_comp);
71
72 BT_HIDDEN
73 int ctf_metadata_decoder_is_packetized(FILE *fp, bool *is_packetized,
74 int *byte_order, bt_logging_level log_level,
75 bt_self_component *self_comp)
76 {
77 uint32_t magic;
78 size_t len;
79 int ret = 0;
80
81 *is_packetized = false;
82 len = fread(&magic, sizeof(magic), 1, fp);
83 if (len != 1) {
84 BT_COMP_LOG_CUR_LVL(BT_LOG_INFO, log_level, self_comp,
85 "Cannot read first metadata packet header: assuming the stream is not packetized.");
86 ret = -1;
87 goto end;
88 }
89
90 if (byte_order) {
91 if (magic == TSDL_MAGIC) {
92 *is_packetized = true;
93 *byte_order = BYTE_ORDER;
94 } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
95 *is_packetized = true;
96 *byte_order = BYTE_ORDER == BIG_ENDIAN ?
97 LITTLE_ENDIAN : BIG_ENDIAN;
98 }
99 }
100
101 end:
102 rewind(fp);
103
104 return ret;
105 }
106
107 BT_HIDDEN
108 struct ctf_metadata_decoder *ctf_metadata_decoder_create(
109 const struct ctf_metadata_decoder_config *config)
110 {
111 struct ctf_metadata_decoder *mdec =
112 g_new0(struct ctf_metadata_decoder, 1);
113
114 BT_ASSERT(config);
115 BT_COMP_LOG_CUR_LVL(BT_LOG_DEBUG, config->log_level, config->self_comp,
116 "Creating CTF metadata decoder: "
117 "clock-class-offset-s=%" PRId64 ", "
118 "clock-class-offset-ns=%" PRId64,
119 config->clock_class_offset_s, config->clock_class_offset_ns);
120
121 if (!mdec) {
122 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, config->log_level,
123 config->self_comp,
124 "Failed to allocate one CTF metadata decoder.");
125 goto end;
126 }
127
128 mdec->log_cfg.log_level = config->log_level;
129 mdec->log_cfg.self_comp = config->self_comp;
130 mdec->scanner = ctf_scanner_alloc();
131 if (!mdec->scanner) {
132 BT_COMP_LOGE("Cannot allocate a metadata lexical scanner: "
133 "mdec-addr=%p", mdec);
134 goto error;
135 }
136
137 mdec->text = g_string_new(NULL);
138 if (!mdec->text) {
139 BT_COMP_LOGE("Failed to allocate one GString: "
140 "mdec-addr=%p", mdec);
141 goto error;
142 }
143
144 mdec->bo = -1;
145 mdec->config = *config;
146 mdec->visitor = ctf_visitor_generate_ir_create(config);
147 if (!mdec->visitor) {
148 BT_COMP_LOGE("Failed to create a CTF IR metadata AST visitor: "
149 "mdec-addr=%p", mdec);
150 goto error;
151 }
152
153 BT_COMP_LOGD("Creating CTF metadata decoder: "
154 "clock-class-offset-s=%" PRId64 ", "
155 "clock-class-offset-ns=%" PRId64 ", addr=%p",
156 config->clock_class_offset_s, config->clock_class_offset_ns,
157 mdec);
158 goto end;
159
160 error:
161 ctf_metadata_decoder_destroy(mdec);
162 mdec = NULL;
163
164 end:
165 return mdec;
166 }
167
168 BT_HIDDEN
169 void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *mdec)
170 {
171 if (!mdec) {
172 return;
173 }
174
175 if (mdec->scanner) {
176 ctf_scanner_free(mdec->scanner);
177 }
178
179 if (mdec->text) {
180 g_string_free(mdec->text, TRUE);
181 }
182
183 BT_COMP_LOGD("Destroying CTF metadata decoder: addr=%p", mdec);
184 ctf_visitor_generate_ir_destroy(mdec->visitor);
185 g_free(mdec);
186 }
187
188 BT_HIDDEN
189 enum ctf_metadata_decoder_status ctf_metadata_decoder_append_content(
190 struct ctf_metadata_decoder *mdec, FILE *fp)
191 {
192 enum ctf_metadata_decoder_status status =
193 CTF_METADATA_DECODER_STATUS_OK;
194 int ret;
195 char *buf = NULL;
196 bool close_fp = false;
197 long start_pos = -1;
198 bool is_packetized;
199
200 BT_ASSERT(mdec);
201 ret = ctf_metadata_decoder_is_packetized(fp, &is_packetized, &mdec->bo,
202 mdec->config.log_level, mdec->config.self_comp);
203 if (ret) {
204 status = CTF_METADATA_DECODER_STATUS_ERROR;
205 goto end;
206 }
207
208 if (is_packetized) {
209 BT_COMP_LOGI("Metadata stream is packetized: mdec-addr=%p", mdec);
210 ret = ctf_metadata_decoder_packetized_file_stream_to_buf(fp,
211 &buf, mdec->bo, &mdec->is_uuid_set,
212 mdec->uuid, mdec->config.log_level,
213 mdec->config.self_comp);
214 if (ret) {
215 BT_COMP_LOGE("Cannot decode packetized metadata packets to metadata text: "
216 "mdec-addr=%p, ret=%d", mdec, ret);
217 status = CTF_METADATA_DECODER_STATUS_ERROR;
218 goto end;
219 }
220
221 if (strlen(buf) == 0) {
222 /* An empty metadata packet is OK. */
223 goto end;
224 }
225
226 /* Convert the real file pointer to a memory file pointer */
227 fp = bt_fmemopen(buf, strlen(buf), "rb");
228 close_fp = true;
229 if (!fp) {
230 BT_COMP_LOGE("Cannot memory-open metadata buffer: %s: "
231 "mdec-addr=%p", strerror(errno), mdec);
232 status = CTF_METADATA_DECODER_STATUS_ERROR;
233 goto end;
234 }
235 } else {
236 unsigned int major, minor;
237 ssize_t nr_items;
238 const long init_pos = ftell(fp);
239
240 BT_COMP_LOGI("Metadata stream is plain text: mdec-addr=%p", mdec);
241
242 if (init_pos < 0) {
243 BT_COMP_LOGE_ERRNO("Failed to get current file position", ".");
244 status = CTF_METADATA_DECODER_STATUS_ERROR;
245 goto end;
246 }
247
248 /* Check text-only metadata header and version */
249 nr_items = fscanf(fp, "/* CTF %10u.%10u", &major, &minor);
250 if (nr_items < 2) {
251 BT_COMP_LOGW("Missing \"/* CTF major.minor\" signature in plain text metadata file stream: "
252 "mdec-addr=%p", mdec);
253 }
254
255 BT_COMP_LOGI("Found metadata stream version in signature: version=%u.%u", major, minor);
256
257 if (!ctf_metadata_decoder_is_packet_version_valid(major,
258 minor)) {
259 BT_COMP_LOGE("Invalid metadata version found in plain text signature: "
260 "version=%u.%u, mdec-addr=%p", major, minor,
261 mdec);
262 status = CTF_METADATA_DECODER_STATUS_INVAL_VERSION;
263 goto end;
264 }
265
266 if (fseek(fp, init_pos, SEEK_SET)) {
267 BT_COMP_LOGE("Cannot seek metadata file stream to initial position: %s: "
268 "mdec-addr=%p", strerror(errno), mdec);
269 status = CTF_METADATA_DECODER_STATUS_ERROR;
270 goto end;
271 }
272 }
273
274 if (BT_LOG_ON_TRACE) {
275 yydebug = 1;
276 }
277
278 /* Save the file's position: we'll seek back to append the plain text */
279 BT_ASSERT(fp);
280
281 if (mdec->config.keep_plain_text) {
282 start_pos = ftell(fp);
283 }
284
285 /* Append the metadata text content */
286 ret = ctf_scanner_append_ast(mdec->scanner, fp);
287 if (ret) {
288 BT_COMP_LOGE("Cannot create the metadata AST out of the metadata text: "
289 "mdec-addr=%p", mdec);
290 status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
291 goto end;
292 }
293
294 /* We know it's complete: append plain text */
295 if (mdec->config.keep_plain_text) {
296 BT_ASSERT(start_pos != -1);
297 ret = fseek(fp, start_pos, SEEK_SET);
298 if (ret) {
299 BT_COMP_LOGE("Failed to seek file: ret=%d, mdec-addr=%p",
300 ret, mdec);
301 status = CTF_METADATA_DECODER_STATUS_ERROR;
302 goto end;
303 }
304
305 ret = bt_common_append_file_content_to_g_string(mdec->text, fp);
306 if (ret) {
307 BT_COMP_LOGE("Failed to append to current plain text: "
308 "ret=%d, mdec-addr=%p", ret, mdec);
309 status = CTF_METADATA_DECODER_STATUS_ERROR;
310 goto end;
311 }
312 }
313
314 ret = ctf_visitor_semantic_check(0, &mdec->scanner->ast->root,
315 &mdec->log_cfg);
316 if (ret) {
317 BT_COMP_LOGE("Validation of the metadata semantics failed: "
318 "mdec-addr=%p", mdec);
319 status = CTF_METADATA_DECODER_STATUS_ERROR;
320 goto end;
321 }
322
323 if (mdec->config.create_trace_class) {
324 ret = ctf_visitor_generate_ir_visit_node(mdec->visitor,
325 &mdec->scanner->ast->root);
326 switch (ret) {
327 case 0:
328 /* Success */
329 break;
330 case -EINCOMPLETE:
331 BT_COMP_LOGD("While visiting metadata AST: incomplete data: "
332 "mdec-addr=%p", mdec);
333 status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
334 goto end;
335 default:
336 BT_COMP_LOGE("Failed to visit AST node to create CTF IR objects: "
337 "mdec-addr=%p, ret=%d", mdec, ret);
338 status = CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR;
339 goto end;
340 }
341 }
342
343 end:
344 yydebug = 0;
345
346 if (fp && close_fp) {
347 if (fclose(fp)) {
348 BT_COMP_LOGE("Cannot close metadata file stream: "
349 "mdec-addr=%p", mdec);
350 }
351 }
352
353 free(buf);
354
355 return status;
356 }
357
358 BT_HIDDEN
359 bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(
360 struct ctf_metadata_decoder *mdec)
361 {
362 BT_ASSERT(mdec);
363 BT_ASSERT(mdec->config.create_trace_class);
364 return ctf_visitor_generate_ir_get_ir_trace_class(mdec->visitor);
365 }
366
367 BT_HIDDEN
368 struct ctf_trace_class *ctf_metadata_decoder_borrow_ctf_trace_class(
369 struct ctf_metadata_decoder *mdec)
370 {
371 BT_ASSERT(mdec);
372 BT_ASSERT(mdec->config.create_trace_class);
373 return ctf_visitor_generate_ir_borrow_ctf_trace_class(mdec->visitor);
374 }
375
376 BT_HIDDEN
377 const char *ctf_metadata_decoder_get_text(struct ctf_metadata_decoder *mdec)
378 {
379 BT_ASSERT(mdec);
380 BT_ASSERT(mdec->config.keep_plain_text);
381 return mdec->text->str;
382 }
383
384 BT_HIDDEN
385 int ctf_metadata_decoder_get_byte_order(struct ctf_metadata_decoder *mdec)
386 {
387 BT_ASSERT(mdec);
388 return mdec->bo;
389 }
390
391 BT_HIDDEN
392 int ctf_metadata_decoder_get_uuid(struct ctf_metadata_decoder *mdec,
393 bt_uuid_t uuid)
394 {
395 int ret = 0;
396
397 BT_ASSERT(mdec);
398
399 if (!mdec->is_uuid_set) {
400 ret = -1;
401 goto end;
402 }
403
404 bt_uuid_copy(uuid, mdec->uuid);
405
406 end:
407 return ret;
408 }
409
410 static
411 enum ctf_metadata_decoder_status find_uuid_in_trace_decl(
412 struct ctf_metadata_decoder *mdec, struct ctf_node *trace_node,
413 bt_uuid_t uuid)
414 {
415 enum ctf_metadata_decoder_status status =
416 CTF_METADATA_DECODER_STATUS_OK;
417 struct ctf_node *entry_node;
418 struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list;
419 char *left = NULL;
420
421 bt_list_for_each_entry(entry_node, decl_list, siblings) {
422 if (entry_node->type == NODE_CTF_EXPRESSION) {
423 int ret;
424
425 left = ctf_ast_concatenate_unary_strings(
426 &entry_node->u.ctf_expression.left);
427 if (!left) {
428 BT_COMP_LOGE("Cannot concatenate unary strings.");
429 status = CTF_METADATA_DECODER_STATUS_ERROR;
430 goto end;
431 }
432
433 if (strcmp(left, "uuid") == 0) {
434 ret = ctf_ast_get_unary_uuid(
435 &entry_node->u.ctf_expression.right,
436 uuid, mdec->config.log_level,
437 mdec->config.self_comp);
438 if (ret) {
439 BT_COMP_LOGE("Invalid trace's `uuid` attribute.");
440 status = CTF_METADATA_DECODER_STATUS_ERROR;
441 goto end;
442 }
443
444 goto end;
445 }
446
447 g_free(left);
448 left = NULL;
449 }
450 }
451
452 status = CTF_METADATA_DECODER_STATUS_NONE;
453
454 end:
455 g_free(left);
456 return status;
457 }
458
459 BT_HIDDEN
460 enum ctf_metadata_decoder_status ctf_metadata_decoder_get_trace_class_uuid(
461 struct ctf_metadata_decoder *mdec, bt_uuid_t uuid)
462 {
463 enum ctf_metadata_decoder_status status =
464 CTF_METADATA_DECODER_STATUS_INCOMPLETE;
465 struct ctf_node *root_node = &mdec->scanner->ast->root;
466 struct ctf_node *trace_node;
467
468 if (!root_node) {
469 status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
470 goto end;
471 }
472
473 trace_node =
474 bt_list_entry(root_node->u.root.trace.next,
475 struct ctf_node, siblings);
476 if (!trace_node) {
477 status = CTF_METADATA_DECODER_STATUS_INCOMPLETE;
478 goto end;
479 }
480
481 status = find_uuid_in_trace_decl(mdec, trace_node, uuid);
482
483 end:
484 return status;
485 }
This page took 0.037499 seconds and 3 git commands to generate.