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