BT_HIDDEN struct ctf_metadata_decoder *ctf_metadata_decoder_create( const struct ctf_metadata_decoder_config *config, const char *name) { struct ctf_metadata_decoder *mdec = g_new0(struct ctf_metadata_decoder, 1); struct ctf_metadata_decoder_config default_config = { .clock_class_offset_s = 0, .clock_class_offset_ns = 0, }; if (!config) { config = &default_config; } BT_LOGD("Creating CTF metadata decoder: " "clock-class-offset-s=%" PRId64 ", " "clock-class-offset-ns=%" PRId64 ", name=\"%s\"", config->clock_class_offset_s, config->clock_class_offset_ns, name); if (!mdec) { BT_LOGE_STR("Failed to allocate one CTF metadata decoder."); goto end; } mdec->config = *config; mdec->visitor = ctf_visitor_generate_ir_create(config, name); if (!mdec->visitor) { BT_LOGE("Failed to create a CTF IR metadata AST visitor: " "mdec-addr=%p", mdec); ctf_metadata_decoder_destroy(mdec); mdec = NULL; goto end; } BT_LOGD("Creating CTF metadata decoder: " "clock-class-offset-s=%" PRId64 ", " "clock-class-offset-ns=%" PRId64 ", " "name=\"%s\", addr=%p", config->clock_class_offset_s, config->clock_class_offset_ns, name, mdec); end: return mdec; } BT_HIDDEN void ctf_metadata_decoder_destroy(struct ctf_metadata_decoder *mdec) { if (!mdec) { return; } BT_LOGD("Destroying CTF metadata decoder: addr=%p", mdec); ctf_visitor_generate_ir_destroy(mdec->visitor); g_free(mdec); } BT_HIDDEN enum ctf_metadata_decoder_status ctf_metadata_decoder_decode( struct ctf_metadata_decoder *mdec, FILE *fp) { enum ctf_metadata_decoder_status status = CTF_METADATA_DECODER_STATUS_OK; int ret; struct ctf_scanner *scanner = NULL; char *buf = NULL; bool close_fp = false; assert(mdec); if (ctf_metadata_decoder_is_packetized(fp, &mdec->bo)) { BT_LOGD("Metadata stream is packetized: mdec-addr=%p", mdec); ret = ctf_metadata_decoder_packetized_file_stream_to_buf_with_mdec( mdec, fp, &buf, mdec->bo); if (ret) { BT_LOGE("Cannot decode packetized metadata packets to metadata text: " "mdec-addr=%p, ret=%d", mdec, ret); status = CTF_METADATA_DECODER_STATUS_ERROR; goto end; } if (strlen(buf) == 0) { /* An empty metadata packet is OK. */ goto end; } /* Convert the real file pointer to a memory file pointer */ fp = bt_fmemopen(buf, strlen(buf), "rb"); close_fp = true; if (!fp) { BT_LOGE("Cannot memory-open metadata buffer: %s: " "mdec-addr=%p", strerror(errno), mdec); status = CTF_METADATA_DECODER_STATUS_ERROR; goto end; } } else { unsigned int major, minor; ssize_t nr_items; const long init_pos = ftell(fp); BT_LOGD("Metadata stream is plain text: mdec-addr=%p", mdec); if (init_pos < 0) { BT_LOGE_ERRNO("Failed to get current file position", "."); status = CTF_METADATA_DECODER_STATUS_ERROR; goto end; } /* Check text-only metadata header and version */ nr_items = fscanf(fp, "/* CTF %10u.%10u", &major, &minor); if (nr_items < 2) { BT_LOGW("Missing \"/* CTF major.minor\" signature in plain text metadata file stream: " "mdec-addr=%p", mdec); } BT_LOGD("Found metadata stream version in signature: version=%u.%u", major, minor); if (!is_version_valid(major, minor)) { BT_LOGE("Invalid metadata version found in plain text signature: " "version=%u.%u, mdec-addr=%p", major, minor, mdec); status = CTF_METADATA_DECODER_STATUS_INVAL_VERSION; goto end; } if (fseek(fp, init_pos, SEEK_SET)) { BT_LOGE("Cannot seek metadata file stream to initial position: %s: " "mdec-addr=%p", strerror(errno), mdec); status = CTF_METADATA_DECODER_STATUS_ERROR; goto end; } } if (BT_LOG_ON_VERBOSE) { yydebug = 1; } /* Allocate a scanner and append the metadata text content */ scanner = ctf_scanner_alloc(); if (!scanner) { BT_LOGE("Cannot allocate a metadata lexical scanner: " "mdec-addr=%p", mdec); status = CTF_METADATA_DECODER_STATUS_ERROR; goto end; } assert(fp); ret = ctf_scanner_append_ast(scanner, fp); if (ret) { BT_LOGE("Cannot create the metadata AST out of the metadata text: " "mdec-addr=%p", mdec); status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; goto end; } ret = ctf_visitor_semantic_check(0, &scanner->ast->root); if (ret) { BT_LOGE("Validation of the metadata semantics failed: " "mdec-addr=%p", mdec); status = CTF_METADATA_DECODER_STATUS_ERROR; goto end; } ret = ctf_visitor_generate_ir_visit_node(mdec->visitor, &scanner->ast->root); switch (ret) { case 0: /* Success */ break; case -EINCOMPLETE: BT_LOGD("While visiting metadata AST: incomplete data: " "mdec-addr=%p", mdec); status = CTF_METADATA_DECODER_STATUS_INCOMPLETE; goto end; default: BT_LOGE("Failed to visit AST node to create CTF IR objects: " "mdec-addr=%p, ret=%d", mdec, ret); status = CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR; goto end; } end: if (scanner) { ctf_scanner_free(scanner); } yydebug = 0; if (fp && close_fp) { if (fclose(fp)) { BT_LOGE("Cannot close metadata file stream: " "mdec-addr=%p", mdec); } } if (buf) { free(buf); } return status; } BT_HIDDEN struct bt_trace *ctf_metadata_decoder_get_trace( struct ctf_metadata_decoder *mdec) { return ctf_visitor_generate_ir_get_trace(mdec->visitor); }
BT_HIDDEN enum lttng_live_iterator_status lttng_live_metadata_update( struct lttng_live_trace *trace) { struct lttng_live_session *session = trace->session; struct lttng_live_metadata *metadata = trace->metadata; struct lttng_live_component *lttng_live = session->lttng_live_msg_iter->lttng_live_comp; ssize_t ret = 0; size_t size, len_read = 0; char *metadata_buf = NULL; FILE *fp = NULL; enum ctf_metadata_decoder_status decoder_status; enum lttng_live_iterator_status status = LTTNG_LIVE_ITERATOR_STATUS_OK; /* No metadata stream yet. */ if (!metadata) { if (session->new_streams_needed) { status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN; } else { session->new_streams_needed = true; status = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE; } goto end; } if (!metadata->trace) { trace->new_metadata_needed = false; } if (!trace->new_metadata_needed) { goto end; } /* Open for writing */ fp = bt_open_memstream(&metadata_buf, &size); if (!fp) { BT_LOGE("Metadata open_memstream: %s", strerror(errno)); goto error; } /* Grab all available metadata. */ do { /* * get_one_metadata_packet returns the number of bytes * received, 0 when we have received everything, a * negative value on error. */ ret = lttng_live_get_one_metadata_packet(trace, fp); if (ret > 0) { len_read += ret; } } while (ret > 0); /* * Consider metadata closed as soon as we get an error reading * it (e.g. cannot be found). */ if (ret < 0) { if (!metadata->closed) { metadata->closed = true; /* * Release our reference on the trace as soon as * we know the metadata stream is not available * anymore. This won't necessarily teardown the * metadata objects immediately, but only when * the data streams are done. */ metadata->trace = NULL; } if (errno == EINTR) { if (lttng_live_graph_is_canceled(lttng_live)) { status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN; goto end; } } } if (bt_close_memstream(&metadata_buf, &size, fp)) { BT_LOGE("bt_close_memstream: %s", strerror(errno)); } ret = 0; fp = NULL; if (len_read == 0) { if (!trace->trace) { status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN; goto end; } trace->new_metadata_needed = false; goto end; } fp = bt_fmemopen(metadata_buf, len_read, "rb"); if (!fp) { BT_LOGE("Cannot memory-open metadata buffer: %s", strerror(errno)); goto error; } /* * The call to ctf_metadata_decoder_decode will append new metadata to * our current trace class. */ decoder_status = ctf_metadata_decoder_decode(metadata->decoder, fp); switch (decoder_status) { case CTF_METADATA_DECODER_STATUS_OK: if (!trace->trace_class) { trace->trace_class = ctf_metadata_decoder_get_ir_trace_class( metadata->decoder); trace->trace = bt_trace_create(trace->trace_class); if (!stream_classes_all_have_default_clock_class( trace->trace_class)) { /* Error logged in function. */ goto error; } trace->clock_class = borrow_any_clock_class(trace->trace_class); } trace->new_metadata_needed = false; break; case CTF_METADATA_DECODER_STATUS_INCOMPLETE: status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN; break; case CTF_METADATA_DECODER_STATUS_ERROR: case CTF_METADATA_DECODER_STATUS_INVAL_VERSION: case CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR: goto error; } goto end; error: status = LTTNG_LIVE_ITERATOR_STATUS_ERROR; end: if (fp) { int closeret; closeret = fclose(fp); if (closeret) { BT_LOGE("Error on fclose"); } } free(metadata_buf); return status; }