Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
0
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;
}