static int add_trace_path(GList **trace_paths, const char *path) { GString *norm_path = NULL; int ret = 0; norm_path = bt_common_normalize_path(path, NULL); if (!norm_path) { BT_LOGE("Failed to normalize path `%s`.", path); ret = -1; goto end; } // FIXME: Remove or ifdef for __MINGW32__ if (strcmp(norm_path->str, "/") == 0) { BT_LOGE("Opening a trace in `/` is not supported."); ret = -1; goto end; } *trace_paths = g_list_prepend(*trace_paths, norm_path); BT_ASSERT(*trace_paths); norm_path = NULL; end: if (norm_path) { g_string_free(norm_path, TRUE); } return ret; }
BT_HIDDEN struct bt_value *bt_attributes_get_field_value(struct bt_value *attr_obj, uint64_t index) { struct bt_value *value_obj = NULL; struct bt_value *attr_field_obj = NULL; if (!attr_obj) { BT_LOGW_STR("Invalid parameter: attributes object is NULL."); goto end; } attr_field_obj = bt_value_array_get(attr_obj, index); if (!attr_field_obj) { BT_LOGE("Cannot get attributes object's array value's element by index: " "value-addr=%p, index=%" PRIu64, attr_obj, index); goto end; } value_obj = bt_value_array_get(attr_field_obj, BT_ATTR_VALUE_INDEX); if (!value_obj) { BT_LOGE("Cannot get attribute array value's element by index: " "value-addr=%p, index=%" PRIu64, attr_field_obj, (uint64_t) BT_ATTR_VALUE_INDEX); } end: BT_PUT(attr_field_obj); return value_obj; }
enum bt_value_status bt_value_map_extend( const struct bt_value *base_map_obj, const struct bt_value *extension_obj, struct bt_value **extended_map_obj) { struct extend_map_element_data extend_data = { .extended_obj = NULL, .status = BT_VALUE_STATUS_OK, }; BT_ASSERT_PRE_NON_NULL(base_map_obj, "Base value object"); BT_ASSERT_PRE_NON_NULL(extension_obj, "Extension value object"); BT_ASSERT_PRE_NON_NULL(extended_map_obj, "Extended value object (output)"); BT_ASSERT_PRE_VALUE_IS_TYPE(base_map_obj, BT_VALUE_TYPE_MAP); BT_ASSERT_PRE_VALUE_IS_TYPE(extension_obj, BT_VALUE_TYPE_MAP); BT_LOGD("Extending map value: base-value-addr=%p, extension-value-addr=%p", base_map_obj, extension_obj); *extended_map_obj = NULL; /* Create copy of base map object to start with */ extend_data.status = bt_value_copy(base_map_obj, extended_map_obj); if (extend_data.status) { BT_LOGE("Cannot copy base value: base-value-addr=%p", base_map_obj); goto error; } BT_ASSERT(extended_map_obj); /* * For each key in the extension map object, replace this key * in the copied map object. */ extend_data.extended_obj = *extended_map_obj; if (bt_value_map_foreach_entry_const(extension_obj, extend_map_element, &extend_data)) { BT_LOGE("Cannot iterate on the extension object's elements: " "extension-value-addr=%p", extension_obj); goto error; } if (extend_data.status) { BT_LOGE("Failed to successfully iterate on the extension object's elements: " "extension-value-addr=%p", extension_obj); goto error; } BT_LOGD("Extended map value: extended-value-addr=%p", *extended_map_obj); goto end; error: BT_OBJECT_PUT_REF_AND_RESET(*extended_map_obj); *extended_map_obj = NULL; end: return extend_data.status; }
int ctf_fs_metadata_set_trace(struct ctf_fs_trace *ctf_fs_trace, struct ctf_fs_metadata_config *config) { int ret = 0; struct ctf_fs_file *file = NULL; struct ctf_metadata_decoder *metadata_decoder = NULL; struct ctf_metadata_decoder_config decoder_config = { .clock_class_offset_s = config ? config->clock_class_offset_s : 0, .clock_class_offset_ns = config ? config->clock_class_offset_ns : 0, }; file = get_file(ctf_fs_trace->path->str); if (!file) { BT_LOGE("Cannot create metadata file object"); ret = -1; goto end; } metadata_decoder = ctf_metadata_decoder_create( config ? &decoder_config : NULL, ctf_fs_trace->name->str); if (!metadata_decoder) { BT_LOGE("Cannot create metadata decoder object"); ret = -1; goto end; } ret = ctf_metadata_decoder_decode(metadata_decoder, file->fp); if (ret) { BT_LOGE("Cannot decode metadata file"); goto end; } ctf_fs_trace->metadata->trace = ctf_metadata_decoder_get_trace( metadata_decoder); assert(ctf_fs_trace->metadata->trace); end: ctf_fs_file_destroy(file); ctf_metadata_decoder_destroy(metadata_decoder); return ret; } int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata) { /* Nothing to initialize for the moment. */ return 0; } void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata) { if (metadata->text) { free(metadata->text); } if (metadata->trace) { BT_PUT(metadata->trace); } }
static struct bt_value *bt_attributes_get_field_by_name( struct bt_value *attr_obj, const char *name) { uint64_t i; int64_t attr_size; struct bt_value *value_obj = NULL; struct bt_value *attr_field_name_obj = NULL; attr_size = bt_value_array_size(attr_obj); if (attr_size < 0) { BT_LOGE("Cannot get array value's size: value-addr=%p", attr_obj); goto error; } for (i = 0; i < attr_size; ++i) { int ret; const char *field_name; value_obj = bt_value_array_get(attr_obj, i); if (!value_obj) { BT_LOGE("Cannot get attributes object's array value's element by index: " "value-addr=%p, index=%" PRIu64, attr_obj, i); goto error; } attr_field_name_obj = bt_value_array_get(value_obj, 0); if (!attr_field_name_obj) { BT_LOGE("Cannot get attribute array value's element by index: " "value-addr=%p, index=%" PRIu64, value_obj, (int64_t) 0); goto error; } ret = bt_value_string_get(attr_field_name_obj, &field_name); if (ret) { BT_LOGE("Cannot get raw value from string value: value-addr=%p", attr_field_name_obj); goto error; } if (!strcmp(field_name, name)) { BT_PUT(attr_field_name_obj); break; } BT_PUT(attr_field_name_obj); BT_PUT(value_obj); } return value_obj; error: BT_PUT(attr_field_name_obj); BT_PUT(value_obj); return value_obj; }
static struct bt_value *bt_value_array_copy(const struct bt_value *array_obj) { int i; int ret; struct bt_value *copy_obj; struct bt_value_array *typed_array_obj; BT_LOGD("Copying array value: addr=%p", array_obj); typed_array_obj = BT_VALUE_TO_ARRAY(array_obj); copy_obj = bt_value_array_create(); if (!copy_obj) { BT_LOGE_STR("Cannot create empty array value."); goto end; } for (i = 0; i < typed_array_obj->garray->len; ++i) { struct bt_value *element_obj_copy = NULL; const struct bt_value *element_obj = bt_value_array_borrow_element_by_index_const( array_obj, i); BT_ASSERT(element_obj); BT_LOGD("Copying array value's element: element-addr=%p, " "index=%d", element_obj, i); ret = bt_value_copy(element_obj, &element_obj_copy); if (ret) { BT_LOGE("Cannot copy array value's element: " "array-addr=%p, index=%d", array_obj, i); BT_OBJECT_PUT_REF_AND_RESET(copy_obj); goto end; } BT_ASSERT(element_obj_copy); ret = bt_value_array_append_element(copy_obj, (void *) element_obj_copy); BT_OBJECT_PUT_REF_AND_RESET(element_obj_copy); if (ret) { BT_LOGE("Cannot append to array value: addr=%p", array_obj); BT_OBJECT_PUT_REF_AND_RESET(copy_obj); goto end; } } BT_LOGD("Copied array value: original-addr=%p, copy-addr=%p", array_obj, copy_obj); end: return copy_obj; }
static struct bt_value *bt_value_map_copy(const struct bt_value *map_obj) { int ret; GHashTableIter iter; gpointer key, element_obj; struct bt_value *copy_obj; struct bt_value *element_obj_copy = NULL; struct bt_value_map *typed_map_obj; BT_LOGD("Copying map value: addr=%p", map_obj); typed_map_obj = BT_VALUE_TO_MAP(map_obj); copy_obj = bt_value_map_create(); if (!copy_obj) { goto end; } g_hash_table_iter_init(&iter, typed_map_obj->ght); while (g_hash_table_iter_next(&iter, &key, &element_obj)) { const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key)); BT_ASSERT(key_str); BT_LOGD("Copying map value's element: element-addr=%p, " "key=\"%s\"", element_obj, key_str); ret = bt_value_copy(element_obj, &element_obj_copy); if (ret) { BT_LOGE("Cannot copy map value's element: " "map-addr=%p, key=\"%s\"", map_obj, key_str); BT_OBJECT_PUT_REF_AND_RESET(copy_obj); goto end; } BT_ASSERT(element_obj_copy); ret = bt_value_map_insert_entry(copy_obj, key_str, (void *) element_obj_copy); BT_OBJECT_PUT_REF_AND_RESET(element_obj_copy); if (ret) { BT_LOGE("Cannot insert into map value: addr=%p, key=\"%s\"", map_obj, key_str); BT_OBJECT_PUT_REF_AND_RESET(copy_obj); goto end; } } BT_LOGD("Copied map value: addr=%p", map_obj); end: return copy_obj; }
BT_HIDDEN int bt_attributes_set_field_value(struct bt_value *attr_obj, const char *name, struct bt_value *value_obj) { int ret = 0; struct bt_value *attr_field_obj = NULL; if (!attr_obj || !name || !value_obj) { BT_LOGW("Invalid parameter: attributes object, name, or value object is NULL: " "attr-value-addr=%p, name-addr=%p, value-addr=%p", attr_obj, name, value_obj); ret = -1; goto end; } attr_field_obj = bt_attributes_get_field_by_name(attr_obj, name); if (attr_field_obj) { ret = bt_value_array_set(attr_field_obj, BT_ATTR_VALUE_INDEX, value_obj); goto end; } attr_field_obj = bt_value_array_create(); if (!attr_field_obj) { BT_LOGE_STR("Failed to create empty array value."); ret = -1; goto end; } ret = bt_value_array_append_string(attr_field_obj, name); ret |= bt_value_array_append(attr_field_obj, value_obj); if (ret) { BT_LOGE("Cannot append elements to array value: addr=%p", attr_field_obj); goto end; } ret = bt_value_array_append(attr_obj, attr_field_obj); if (ret) { BT_LOGE("Cannot append element to array value: " "array-value-addr=%p, element-value-addr=%p", attr_obj, attr_field_obj); } end: BT_PUT(attr_field_obj); return ret; }
static int stack_push(struct stack *stack, struct bt_field_type *base_type, size_t base_len) { int ret = 0; struct stack_entry *entry; assert(stack); assert(base_type); BT_LOGV("Pushing field type on stack: stack-addr=%p, " "ft-addr=%p, ft-id=%s, base-length=%zu, " "stack-size-before=%u, stack-size-after=%u", stack, base_type, bt_field_type_id_string( bt_field_type_get_type_id(base_type)), base_len, stack->entries->len, stack->entries->len + 1); entry = g_new0(struct stack_entry, 1); if (!entry) { BT_LOGE("Failed to allocate one stack entry: stack-addr=%p", stack); ret = BT_BTR_STATUS_ERROR; goto end; } entry->base_type = base_type; bt_get(entry->base_type); entry->base_len = base_len; g_ptr_array_add(stack->entries, entry); end: return ret; }
static bool stream_classes_all_have_default_clock_class(bt_trace_class *tc) { uint64_t i, sc_count; const bt_clock_class *cc = NULL; const bt_stream_class *sc; bool ret = true; sc_count = bt_trace_class_get_stream_class_count(tc); for (i = 0; i < sc_count; i++) { sc = bt_trace_class_borrow_stream_class_by_index_const(tc, i); BT_ASSERT(sc); cc = bt_stream_class_borrow_default_clock_class_const(sc); if (!cc) { ret = false; BT_LOGE("Stream class doesn't have a default clock class: " "sc-id=%" PRIu64 ", sc-name=\"%s\"", bt_stream_class_get_id(sc), bt_stream_class_get_name(sc)); goto end; } } end: return ret; }
BT_HIDDEN struct bt_value *bt_attributes_get_field_value_by_name( struct bt_value *attr_obj, const char *name) { struct bt_value *value_obj = NULL; struct bt_value *attr_field_obj = NULL; if (!attr_obj || !name) { BT_LOGW("Invalid parameter: attributes object or name is NULL: " "value-addr=%p, name-addr=%p", attr_obj, name); goto end; } attr_field_obj = bt_attributes_get_field_by_name(attr_obj, name); if (!attr_field_obj) { BT_LOGD("Cannot find attributes object's field by name: " "value-addr=%p, name=\"%s\"", attr_obj, name); goto end; } value_obj = bt_value_array_get(attr_field_obj, BT_ATTR_VALUE_INDEX); if (!value_obj) { BT_LOGE("Cannot get attribute array value's element by index: " "value-addr=%p, index=%" PRIu64, attr_field_obj, (uint64_t) BT_ATTR_VALUE_INDEX); } end: BT_PUT(attr_field_obj); return value_obj; }
bool read_src_fs_parameters(const bt_value *params, const bt_value **paths, struct ctf_fs_component *ctf_fs) { bool ret; const bt_value *value; /* paths parameter */ *paths = bt_value_map_borrow_entry_value_const(params, "paths"); if (!validate_paths_parameter(*paths)) { goto error; } /* clock-class-offset-s parameter */ value = bt_value_map_borrow_entry_value_const(params, "clock-class-offset-s"); if (value) { if (!bt_value_is_signed_integer(value)) { BT_LOGE("clock-class-offset-s must be an integer"); goto error; } ctf_fs->metadata_config.clock_class_offset_s = bt_value_signed_integer_get(value); } /* clock-class-offset-ns parameter */ value = bt_value_map_borrow_entry_value_const(params, "clock-class-offset-ns"); if (value) { if (!bt_value_is_signed_integer(value)) { BT_LOGE("clock-class-offset-ns must be an integer"); goto error; } ctf_fs->metadata_config.clock_class_offset_ns = bt_value_signed_integer_get(value); } ret = true; goto end; error: ret = false; end: return ret; }
BT_HIDDEN const char *bt_attributes_get_field_name(struct bt_value *attr_obj, uint64_t index) { int rc; const char *ret = NULL; struct bt_value *attr_field_obj = NULL; struct bt_value *attr_field_name_obj = NULL; if (!attr_obj) { BT_LOGW_STR("Invalid parameter: attributes object is NULL."); goto end; } attr_field_obj = bt_value_array_get(attr_obj, index); if (!attr_field_obj) { BT_LOGE("Cannot get attributes object's array value's element by index: " "value-addr=%p, index=%" PRIu64, attr_obj, index); goto end; } attr_field_name_obj = bt_value_array_get(attr_field_obj, BT_ATTR_NAME_INDEX); if (!attr_field_name_obj) { BT_LOGE("Cannot get attribute array value's element by index: " "value-addr=%p, index=%" PRIu64, attr_field_obj, (uint64_t) BT_ATTR_NAME_INDEX); goto end; } rc = bt_value_string_get(attr_field_name_obj, &ret); if (rc) { BT_LOGE("Cannot get raw value from string value: value-addr=%p", attr_field_name_obj); ret = NULL; } end: BT_PUT(attr_field_name_obj); BT_PUT(attr_field_obj); return ret; }
static bt_bool extend_map_element(const char *key, const struct bt_value *extension_obj_elem, void *data) { bt_bool ret = BT_TRUE; struct extend_map_element_data *extend_data = data; struct bt_value *extension_obj_elem_copy = NULL; /* Copy object which is to replace the current one */ extend_data->status = bt_value_copy(extension_obj_elem, &extension_obj_elem_copy); if (extend_data->status) { BT_LOGE("Cannot copy map element: addr=%p", extension_obj_elem); goto error; } BT_ASSERT(extension_obj_elem_copy); /* Replace in extended object */ extend_data->status = bt_value_map_insert_entry( extend_data->extended_obj, key, (void *) extension_obj_elem_copy); if (extend_data->status) { BT_LOGE("Cannot replace value in extended value: key=\"%s\", " "extended-value-addr=%p, element-value-addr=%p", key, extend_data->extended_obj, extension_obj_elem_copy); goto error; } goto end; error: BT_ASSERT(extend_data->status != BT_VALUE_STATUS_OK); ret = BT_FALSE; end: BT_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy); return ret; }
static bool validate_paths_parameter(const bt_value *paths) { bool ret; bt_value_type type; uint64_t i; if (!paths) { BT_LOGE("missing \"paths\" parameter"); goto error; } type = bt_value_get_type(paths); if (type != BT_VALUE_TYPE_ARRAY) { BT_LOGE("`paths` parameter: expecting array value: type=%s", bt_common_value_type_string(type)); goto error; } for (i = 0; i < bt_value_array_get_size(paths); i++) { const bt_value *elem; elem = bt_value_array_borrow_element_by_index_const(paths, i); type = bt_value_get_type(elem); if (type != BT_VALUE_TYPE_STRING) { BT_LOGE("`paths` parameter: expecting string value: index=%" PRIu64 ", type=%s", i, bt_common_value_type_string(type)); goto error; } } ret = true; goto end; error: ret = false; end: return ret; }
struct bt_ctf_field_type * bt_ctf_event_class_get_payload_type_field_type_by_name( struct bt_ctf_event_class *event_class, const char *name) { GQuark name_quark; struct bt_ctf_field_type *field_type = NULL; if (!event_class || !name) { BT_LOGW("Invalid parameter: event class or name is NULL: " "event-class-addr=%p, name-addr=%p", event_class, name); goto end; } if (!event_class->common.payload_field_type) { BT_LOGV("Event class has no payload field type: " "addr=%p, name=\"%s\", id=%" PRId64, event_class, bt_ctf_event_class_get_name(event_class), bt_ctf_event_class_get_id(event_class)); goto end; } BT_ASSERT(bt_ctf_field_type_common_get_type_id( event_class->common.payload_field_type) == BT_CTF_FIELD_TYPE_ID_STRUCT); name_quark = g_quark_try_string(name); if (!name_quark) { BT_LOGE("Cannot get GQuark: string=\"%s\"", name); goto end; } /* * No need to increment field_type's reference count since getting it * from the structure already does. */ field_type = (void *) bt_ctf_field_type_structure_get_field_type_by_name( (void *) event_class->common.payload_field_type, name); end: return field_type; }
BT_HIDDEN int bt_attributes_freeze(struct bt_value *attr_obj) { uint64_t i; int64_t count; int ret = 0; if (!attr_obj) { BT_LOGW_STR("Invalid parameter: attributes object is NULL."); ret = -1; goto end; } BT_LOGD("Freezing attributes object: value-addr=%p", attr_obj); count = bt_value_array_size(attr_obj); assert(count >= 0); /* * We do not freeze the array value object itself here, since * internal stuff could need to modify/add attributes. Each * attribute is frozen one by one. */ for (i = 0; i < count; ++i) { struct bt_value *obj = NULL; obj = bt_attributes_get_field_value(attr_obj, i); if (!obj) { BT_LOGE("Cannot get attributes object's field value by index: " "value-addr=%p, index=%" PRIu64, attr_obj, i); ret = -1; goto end; } bt_value_freeze(obj); BT_PUT(obj); } end: return ret; }
BT_HIDDEN bt_query_status ctf_fs_query( bt_self_component_class_source *comp_class, const bt_query_executor *query_exec, const char *object, const bt_value *params, const bt_value **result) { bt_query_status status = BT_QUERY_STATUS_OK; if (!strcmp(object, "metadata-info")) { status = metadata_info_query(comp_class, params, result); } else if (!strcmp(object, "trace-info")) { status = trace_info_query(comp_class, params, result); } else { BT_LOGE("Unknown query object `%s`", object); status = BT_QUERY_STATUS_INVALID_OBJECT; goto end; } end: return status; }
static int create_ports_for_trace(struct ctf_fs_component *ctf_fs, struct ctf_fs_trace *ctf_fs_trace) { int ret = 0; size_t i; /* Create one output port for each stream file group */ for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) { struct ctf_fs_ds_file_group *ds_file_group = g_ptr_array_index(ctf_fs_trace->ds_file_groups, i); ret = create_one_port_for_trace(ctf_fs, ctf_fs_trace, ds_file_group); if (ret) { BT_LOGE("Cannot create output port."); goto end; } } end: return ret; }
struct bt_event *bt_event_create(struct bt_event_class *event_class) { int ret; enum bt_validation_flag validation_flags = BT_VALIDATION_FLAG_STREAM | BT_VALIDATION_FLAG_EVENT; struct bt_event *event = NULL; struct bt_trace *trace = NULL; struct bt_stream_class *stream_class = NULL; struct bt_field_type *packet_header_type = NULL; struct bt_field_type *packet_context_type = NULL; struct bt_field_type *event_header_type = NULL; struct bt_field_type *stream_event_ctx_type = NULL; struct bt_field_type *event_context_type = NULL; struct bt_field_type *event_payload_type = NULL; struct bt_field *event_header = NULL; struct bt_field *stream_event_context = NULL; struct bt_field *event_context = NULL; struct bt_field *event_payload = NULL; struct bt_value *environment = NULL; struct bt_validation_output validation_output = { 0 }; int trace_valid = 0; BT_LOGD("Creating event object: event-class-addr=%p, " "event-class-name=\"%s\", event-class-id=%" PRId64, event_class, bt_event_class_get_name(event_class), bt_event_class_get_id(event_class)); if (!event_class) { BT_LOGW_STR("Invalid parameter: event class is NULL."); goto error; } stream_class = bt_event_class_get_stream_class(event_class); /* * We disallow the creation of an event if its event class has not been * associated to a stream class. */ if (!stream_class) { BT_LOGW_STR("Event class is not part of a stream class."); goto error; } /* The event class was frozen when added to its stream class */ assert(event_class->frozen); /* Validate the trace (if any), the stream class, and the event class */ trace = bt_stream_class_get_trace(stream_class); if (trace) { BT_LOGD_STR("Event's class is part of a trace."); packet_header_type = bt_trace_get_packet_header_type(trace); trace_valid = trace->valid; assert(trace_valid); environment = trace->environment; } packet_context_type = bt_stream_class_get_packet_context_type( stream_class); event_header_type = bt_stream_class_get_event_header_type( stream_class); stream_event_ctx_type = bt_stream_class_get_event_context_type( stream_class); event_context_type = bt_event_class_get_context_type(event_class); event_payload_type = bt_event_class_get_payload_type(event_class); ret = bt_validate_class_types(environment, packet_header_type, packet_context_type, event_header_type, stream_event_ctx_type, event_context_type, event_payload_type, trace_valid, stream_class->valid, event_class->valid, &validation_output, validation_flags); BT_PUT(packet_header_type); BT_PUT(packet_context_type); BT_PUT(event_header_type); BT_PUT(stream_event_ctx_type); BT_PUT(event_context_type); BT_PUT(event_payload_type); if (ret) { /* * This means something went wrong during the validation * process, not that the objects are invalid. */ BT_LOGE("Failed to validate event and parents: ret=%d", ret); goto error; } if ((validation_output.valid_flags & validation_flags) != validation_flags) { /* Invalid trace/stream class/event class */ BT_LOGW("Invalid trace, stream class, or event class: " "valid-flags=0x%x", validation_output.valid_flags); goto error; } /* * At this point we know the trace (if associated to the stream * class), the stream class, and the event class, with their * current types, are valid. We may proceed with creating * the event. */ event = g_new0(struct bt_event, 1); if (!event) { BT_LOGE_STR("Failed to allocate one event."); goto error; } bt_object_init(event, bt_event_destroy); /* * event does not share a common ancestor with the event class; it has * to guarantee its existence by holding a reference. This reference * shall be released once the event is associated to a stream since, * from that point, the event and its class will share the same * lifetime. */ event->event_class = bt_get(event_class); event->clock_values = g_hash_table_new_full(g_direct_hash, g_direct_equal, bt_put, bt_put); if (validation_output.event_header_type) { BT_LOGD("Creating initial event header field: ft-addr=%p", validation_output.event_header_type); event_header = bt_field_create(validation_output.event_header_type); if (!event_header) { BT_LOGE_STR("Cannot create initial event header field object."); goto error; } } if (validation_output.stream_event_ctx_type) { BT_LOGD("Creating initial stream event context field: ft-addr=%p", validation_output.stream_event_ctx_type); stream_event_context = bt_field_create( validation_output.stream_event_ctx_type); if (!stream_event_context) { BT_LOGE_STR("Cannot create initial stream event context field object."); goto error; } } if (validation_output.event_context_type) { BT_LOGD("Creating initial event context field: ft-addr=%p", validation_output.event_context_type); event_context = bt_field_create( validation_output.event_context_type); if (!event_context) { BT_LOGE_STR("Cannot create initial event context field object."); goto error; } } if (validation_output.event_payload_type) { BT_LOGD("Creating initial event payload field: ft-addr=%p", validation_output.event_payload_type); event_payload = bt_field_create( validation_output.event_payload_type); if (!event_payload) { BT_LOGE_STR("Cannot create initial event payload field object."); goto error; } } /* * At this point all the fields are created, potentially from * validated copies of field types, so that the field types and * fields can be replaced in the trace, stream class, * event class, and created event. */ bt_validation_replace_types(trace, stream_class, event_class, &validation_output, validation_flags); BT_MOVE(event->event_header, event_header); BT_MOVE(event->stream_event_context, stream_event_context); BT_MOVE(event->context_payload, event_context); BT_MOVE(event->fields_payload, event_payload); /* * Put what was not moved in bt_validation_replace_types(). */ bt_validation_output_put_types(&validation_output); /* * Freeze the stream class since the event header must not be changed * anymore. */ bt_stream_class_freeze(stream_class); /* * Mark stream class, and event class as valid since * they're all frozen now. */ stream_class->valid = 1; event_class->valid = 1; /* Put stuff we borrowed from the event class */ BT_PUT(stream_class); BT_PUT(trace); BT_LOGD("Created event object: addr=%p, event-class-name=\"%s\", " "event-class-id=%" PRId64, event, bt_event_class_get_name(event->event_class), bt_event_class_get_id(event_class)); return event; error: bt_validation_output_put_types(&validation_output); BT_PUT(event); BT_PUT(stream_class); BT_PUT(trace); BT_PUT(event_header); BT_PUT(stream_event_context); BT_PUT(event_context); BT_PUT(event_payload); assert(!packet_header_type); assert(!packet_context_type); assert(!event_header_type); assert(!stream_event_ctx_type); assert(!event_context_type); assert(!event_payload_type); return event; }
static struct bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info) { struct bt_plugin *plugin = NULL; PyObject *py_name = NULL; PyObject *py_author = NULL; PyObject *py_description = NULL; PyObject *py_license = NULL; PyObject *py_version = NULL; PyObject *py_comp_class_addrs = NULL; const char *name = NULL; const char *author = NULL; const char *description = NULL; const char *license = NULL; unsigned int major = 0, minor = 0, patch = 0; const char *version_extra = NULL; int ret; assert(plugin_info); assert(python_state == PYTHON_STATE_FULLY_INITIALIZED); py_name = PyObject_GetAttrString(plugin_info, "name"); if (!py_name) { BT_LOGW("Cannot find `name` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); goto error; } py_author = PyObject_GetAttrString(plugin_info, "author"); if (!py_author) { BT_LOGW("Cannot find `author` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); goto error; } py_description = PyObject_GetAttrString(plugin_info, "description"); if (!py_description) { BT_LOGW("Cannot find `desciption` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); goto error; } py_license = PyObject_GetAttrString(plugin_info, "license"); if (!py_license) { BT_LOGW("Cannot find `license` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); goto error; } py_version = PyObject_GetAttrString(plugin_info, "version"); if (!py_version) { BT_LOGW("Cannot find `version` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); goto error; } py_comp_class_addrs = PyObject_GetAttrString(plugin_info, "comp_class_addrs"); if (!py_comp_class_addrs) { BT_LOGW("Cannot find `comp_class_addrs` attribute in Python plugin info object: " "py-plugin-info-addr=%p", plugin_info); goto error; } if (PyUnicode_Check(py_name)) { name = PyUnicode_AsUTF8(py_name); if (!name) { BT_LOGW("Cannot decode Python plugin name string: " "py-plugin-info-addr=%p", plugin_info); goto error; } } else { /* Plugin name is mandatory */ BT_LOGW("Plugin name is not a string: " "py-plugin-info-addr=%p", plugin_info); goto error; } if (PyUnicode_Check(py_author)) { author = PyUnicode_AsUTF8(py_author); if (!author) { BT_LOGW("Cannot decode Python plugin author string: " "py-plugin-info-addr=%p", plugin_info); goto error; } } if (PyUnicode_Check(py_description)) { description = PyUnicode_AsUTF8(py_description); if (!description) { BT_LOGW("Cannot decode Python plugin description string: " "py-plugin-info-addr=%p", plugin_info); goto error; } } if (PyUnicode_Check(py_license)) { license = PyUnicode_AsUTF8(py_license); if (!license) { BT_LOGW("Cannot decode Python plugin license string: " "py-plugin-info-addr=%p", plugin_info); goto error; } } if (PyTuple_Check(py_version)) { if (PyTuple_Size(py_version) >= 3) { PyObject *py_major = PyTuple_GetItem(py_version, 0); PyObject *py_minor = PyTuple_GetItem(py_version, 1); PyObject *py_patch = PyTuple_GetItem(py_version, 2); assert(py_major); assert(py_minor); assert(py_patch); if (PyLong_Check(py_major)) { major = PyLong_AsUnsignedLong(py_major); } if (PyLong_Check(py_minor)) { minor = PyLong_AsUnsignedLong(py_minor); } if (PyLong_Check(py_patch)) { patch = PyLong_AsUnsignedLong(py_patch); } if (PyErr_Occurred()) { /* Overflow error, most probably */ BT_LOGW("Invalid Python plugin version format: " "py-plugin-info-addr=%p", plugin_info); goto error; } } if (PyTuple_Size(py_version) >= 4) { PyObject *py_extra = PyTuple_GetItem(py_version, 3); assert(py_extra); if (PyUnicode_Check(py_extra)) { version_extra = PyUnicode_AsUTF8(py_extra); if (!version_extra) { BT_LOGW("Cannot decode Python plugin version's extra string: " "py-plugin-info-addr=%p", plugin_info); goto error; } } } } plugin = bt_plugin_create_empty(BT_PLUGIN_TYPE_PYTHON); if (!plugin) { BT_LOGE_STR("Cannot create empty plugin object."); goto error; } bt_plugin_set_name(plugin, name); if (description) { bt_plugin_set_description(plugin, description); } if (author) { bt_plugin_set_author(plugin, author); } if (license) { bt_plugin_set_license(plugin, license); } bt_plugin_set_version(plugin, major, minor, patch, version_extra); if (PyList_Check(py_comp_class_addrs)) { size_t i; for (i = 0; i < PyList_Size(py_comp_class_addrs); i++) { struct bt_component_class *comp_class; PyObject *py_comp_class_addr; py_comp_class_addr = PyList_GetItem(py_comp_class_addrs, i); assert(py_comp_class_addr); if (PyLong_Check(py_comp_class_addr)) { comp_class = (struct bt_component_class *) PyLong_AsUnsignedLongLong(py_comp_class_addr); } else { BT_LOGW("Component class address is not an integer in Python plugin info object: " "py-plugin-info-addr=%p, index=%zu", plugin_info, i); continue; } ret = bt_plugin_add_component_class(plugin, comp_class); if (ret < 0) { BT_LOGE("Cannot add component class to plugin: " "py-plugin-info-addr=%p, " "plugin-addr=%p, plugin-name=\"%s\", " "comp-class-addr=%p, " "comp-class-name=\"%s\", " "comp-class-type=%s", plugin_info, plugin, bt_plugin_get_name(plugin), comp_class, bt_component_class_get_name(comp_class), bt_component_class_type_string( bt_component_class_get_type(comp_class))); continue; } } } bt_plugin_freeze(plugin); goto end; error: print_python_traceback_warn(); pyerr_clear(); BT_PUT(plugin); end: Py_XDECREF(py_name); Py_XDECREF(py_author); Py_XDECREF(py_description); Py_XDECREF(py_license); Py_XDECREF(py_version); Py_XDECREF(py_comp_class_addrs); return plugin; }
static int create_ds_file_groups(struct ctf_fs_trace *ctf_fs_trace) { int ret = 0; const char *basename; GError *error = NULL; GDir *dir = NULL; /* Check each file in the path directory, except specific ones */ dir = g_dir_open(ctf_fs_trace->path->str, 0, &error); if (!dir) { BT_LOGE("Cannot open directory `%s`: %s (code %d)", ctf_fs_trace->path->str, error->message, error->code); goto error; } while ((basename = g_dir_read_name(dir))) { struct ctf_fs_file *file; if (!strcmp(basename, CTF_FS_METADATA_FILENAME)) { /* Ignore the metadata stream. */ BT_LOGD("Ignoring metadata file `%s" G_DIR_SEPARATOR_S "%s`", ctf_fs_trace->path->str, basename); continue; } if (basename[0] == '.') { BT_LOGD("Ignoring hidden file `%s" G_DIR_SEPARATOR_S "%s`", ctf_fs_trace->path->str, basename); continue; } /* Create the file. */ file = ctf_fs_file_create(); if (!file) { BT_LOGE("Cannot create stream file object for file `%s" G_DIR_SEPARATOR_S "%s`", ctf_fs_trace->path->str, basename); goto error; } /* Create full path string. */ g_string_append_printf(file->path, "%s" G_DIR_SEPARATOR_S "%s", ctf_fs_trace->path->str, basename); if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) { BT_LOGD("Ignoring non-regular file `%s`", file->path->str); ctf_fs_file_destroy(file); file = NULL; continue; } ret = ctf_fs_file_open(file, "rb"); if (ret) { BT_LOGE("Cannot open stream file `%s`", file->path->str); goto error; } if (file->size == 0) { /* Skip empty stream. */ BT_LOGD("Ignoring empty file `%s`", file->path->str); ctf_fs_file_destroy(file); continue; } ret = add_ds_file_to_ds_file_group(ctf_fs_trace, file->path->str); if (ret) { BT_LOGE("Cannot add stream file `%s` to stream file group", file->path->str); ctf_fs_file_destroy(file); goto error; } ctf_fs_file_destroy(file); } goto end; error: ret = -1; end: if (dir) { g_dir_close(dir); dir = NULL; } if (error) { g_error_free(error); } return ret; }
static int add_ds_file_to_ds_file_group(struct ctf_fs_trace *ctf_fs_trace, const char *path) { int64_t stream_instance_id = -1; int64_t begin_ns = -1; struct ctf_fs_ds_file_group *ds_file_group = NULL; bool add_group = false; int ret; size_t i; struct ctf_fs_ds_file *ds_file = NULL; struct ctf_fs_ds_index *index = NULL; struct bt_msg_iter *msg_iter = NULL; struct ctf_stream_class *sc = NULL; struct bt_msg_iter_packet_properties props; msg_iter = bt_msg_iter_create(ctf_fs_trace->metadata->tc, bt_common_get_page_size() * 8, ctf_fs_ds_file_medops, NULL); if (!msg_iter) { BT_LOGE_STR("Cannot create a CTF message iterator."); goto error; } ds_file = ctf_fs_ds_file_create(ctf_fs_trace, NULL, msg_iter, NULL, path); if (!ds_file) { goto error; } ret = bt_msg_iter_get_packet_properties(ds_file->msg_iter, &props); if (ret) { BT_LOGE("Cannot get stream file's first packet's header and context fields (`%s`).", path); goto error; } sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc, props.stream_class_id); BT_ASSERT(sc); stream_instance_id = props.data_stream_id; if (props.snapshots.beginning_clock != UINT64_C(-1)) { BT_ASSERT(sc->default_clock_class); ret = bt_util_clock_cycles_to_ns_from_origin( props.snapshots.beginning_clock, sc->default_clock_class->frequency, sc->default_clock_class->offset_seconds, sc->default_clock_class->offset_cycles, &begin_ns); if (ret) { BT_LOGE("Cannot convert clock cycles to nanoseconds from origin (`%s`).", path); goto error; } } index = ctf_fs_ds_file_build_index(ds_file); if (!index) { BT_LOGW("Failed to index CTF stream file \'%s\'", ds_file->file->path->str); } if (begin_ns == -1) { /* * No beggining timestamp to sort the stream files * within a stream file group, so consider that this * file must be the only one within its group. */ stream_instance_id = -1; } if (stream_instance_id == -1) { /* * No stream instance ID or no beginning timestamp: * create a unique stream file group for this stream * file because, even if there's a stream instance ID, * there's no timestamp to order the file within its * group. */ ds_file_group = ctf_fs_ds_file_group_create(ctf_fs_trace, sc, UINT64_C(-1)); if (!ds_file_group) { goto error; } ret = ctf_fs_ds_file_group_add_ds_file_info(ds_file_group, path, begin_ns, index); /* Ownership of index is transferred. */ index = NULL; if (ret) { goto error; } add_group = true; goto end; } BT_ASSERT(stream_instance_id != -1); BT_ASSERT(begin_ns != -1); /* Find an existing stream file group with this ID */ for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) { ds_file_group = g_ptr_array_index( ctf_fs_trace->ds_file_groups, i); if (ds_file_group->sc == sc && ds_file_group->stream_id == stream_instance_id) { break; } ds_file_group = NULL; } if (!ds_file_group) { ds_file_group = ctf_fs_ds_file_group_create(ctf_fs_trace, sc, stream_instance_id); if (!ds_file_group) { goto error; } add_group = true; } ret = ctf_fs_ds_file_group_add_ds_file_info(ds_file_group, path, begin_ns, index); index = NULL; if (ret) { goto error; } goto end; error: ctf_fs_ds_file_group_destroy(ds_file_group); ds_file_group = NULL; ret = -1; end: if (add_group && ds_file_group) { g_ptr_array_add(ctf_fs_trace->ds_file_groups, ds_file_group); } ctf_fs_ds_file_destroy(ds_file); if (msg_iter) { bt_msg_iter_destroy(msg_iter); } ctf_fs_ds_index_destroy(index); return ret; }
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; }
static int create_streams_for_trace(struct ctf_fs_trace *ctf_fs_trace) { int ret; GString *name = NULL; guint i; for (i = 0; i < ctf_fs_trace->ds_file_groups->len; i++) { struct ctf_fs_ds_file_group *ds_file_group = g_ptr_array_index(ctf_fs_trace->ds_file_groups, i); name = get_stream_instance_unique_name(ds_file_group); if (!name) { goto error; } if (ds_file_group->sc->ir_sc) { BT_ASSERT(ctf_fs_trace->trace); if (ds_file_group->stream_id == UINT64_C(-1)) { /* No stream ID: use 0 */ ds_file_group->stream = bt_stream_create_with_id( ds_file_group->sc->ir_sc, ctf_fs_trace->trace, ctf_fs_trace->next_stream_id); ctf_fs_trace->next_stream_id++; } else { /* Specific stream ID */ ds_file_group->stream = bt_stream_create_with_id( ds_file_group->sc->ir_sc, ctf_fs_trace->trace, (uint64_t) ds_file_group->stream_id); } } else { ds_file_group->stream = NULL; } if (!ds_file_group->stream) { BT_LOGE("Cannot create stream for DS file group: " "addr=%p, stream-name=\"%s\"", ds_file_group, name->str); goto error; } ret = bt_stream_set_name(ds_file_group->stream, name->str); if (ret) { BT_LOGE("Cannot set stream's name: " "addr=%p, stream-name=\"%s\"", ds_file_group->stream, name->str); goto error; } g_string_free(name, TRUE); name = NULL; } ret = 0; goto end; error: ret = -1; end: if (name) { g_string_free(name, TRUE); } return ret; }
static int ctf_fs_component_create_ctf_fs_traces_one_root(bt_self_component_source *self_comp, struct ctf_fs_component *ctf_fs, const char *path_param) { struct ctf_fs_trace *ctf_fs_trace = NULL; int ret = 0; GString *norm_path = NULL; GList *trace_paths = NULL; GList *trace_names = NULL; GList *tp_node; GList *tn_node; norm_path = bt_common_normalize_path(path_param, NULL); if (!norm_path) { BT_LOGE("Failed to normalize path: `%s`.", path_param); goto error; } ret = ctf_fs_find_traces(&trace_paths, norm_path->str); if (ret) { goto error; } if (!trace_paths) { BT_LOGE("No CTF traces recursively found in `%s`.", path_param); goto error; } trace_names = ctf_fs_create_trace_names(trace_paths, norm_path->str); if (!trace_names) { BT_LOGE("Cannot create trace names from trace paths."); goto error; } for (tp_node = trace_paths, tn_node = trace_names; tp_node; tp_node = g_list_next(tp_node), tn_node = g_list_next(tn_node)) { GString *trace_path = tp_node->data; GString *trace_name = tn_node->data; ctf_fs_trace = ctf_fs_trace_create(self_comp, trace_path->str, trace_name->str, &ctf_fs->metadata_config); if (!ctf_fs_trace) { BT_LOGE("Cannot create trace for `%s`.", trace_path->str); goto error; } g_ptr_array_add(ctf_fs->traces, ctf_fs_trace); ctf_fs_trace = NULL; } goto end; error: ret = -1; ctf_fs_trace_destroy(ctf_fs_trace); end: for (tp_node = trace_paths; tp_node; tp_node = g_list_next(tp_node)) { if (tp_node->data) { g_string_free(tp_node->data, TRUE); } } for (tn_node = trace_names; tn_node; tn_node = g_list_next(tn_node)) { if (tn_node->data) { g_string_free(tn_node->data, TRUE); } } if (trace_paths) { g_list_free(trace_paths); } if (trace_names) { g_list_free(trace_names); } if (norm_path) { g_string_free(norm_path, TRUE); } return ret; }
static int ctf_fs_find_traces(GList **trace_paths, const char *start_path) { int ret; GError *error = NULL; GDir *dir = NULL; const char *basename = NULL; /* Check if the starting path is a CTF trace itself */ ret = path_is_ctf_trace(start_path); if (ret < 0) { goto end; } if (ret) { /* * Stop recursion: a CTF trace cannot contain another * CTF trace. */ ret = add_trace_path(trace_paths, start_path); goto end; } /* Look for subdirectories */ if (!g_file_test(start_path, G_FILE_TEST_IS_DIR)) { /* Starting path is not a directory: end of recursion */ goto end; } dir = g_dir_open(start_path, 0, &error); if (!dir) { if (error->code == G_FILE_ERROR_ACCES) { BT_LOGD("Cannot open directory `%s`: %s (code %d): continuing", start_path, error->message, error->code); goto end; } BT_LOGE("Cannot open directory `%s`: %s (code %d)", start_path, error->message, error->code); ret = -1; goto end; } while ((basename = g_dir_read_name(dir))) { GString *sub_path = g_string_new(NULL); if (!sub_path) { ret = -1; goto end; } g_string_printf(sub_path, "%s" G_DIR_SEPARATOR_S "%s", start_path, basename); ret = ctf_fs_find_traces(trace_paths, sub_path->str); g_string_free(sub_path, TRUE); if (ret) { goto end; } } end: if (dir) { g_dir_close(dir); } if (error) { g_error_free(error); } return ret; }
static int ctf_metadata_decoder_packetized_file_stream_to_buf_with_mdec( struct ctf_metadata_decoder *mdec, FILE *fp, char **buf, int byte_order) { FILE *out_fp; size_t size; int ret = 0; int tret; size_t packet_index = 0; out_fp = bt_open_memstream(buf, &size); if (out_fp == NULL) { BT_LOGE("Cannot open memory stream: %s: mdec-addr=%p", strerror(errno), mdec); goto error; } for (;;) { if (feof(fp) != 0) { break; } tret = decode_packet(mdec, fp, out_fp, byte_order); if (tret) { BT_LOGE("Cannot decode packet: index=%zu, mdec-addr=%p", packet_index, mdec); goto error; } packet_index++; } /* Make sure the whole string ends with a null character */ tret = fputc('\0', out_fp); if (tret == EOF) { BT_LOGE("Cannot append '\\0' to the decoded metadata buffer: " "mdec-addr=%p", mdec); goto error; } /* Close stream, which also flushes the buffer */ ret = bt_close_memstream(buf, &size, out_fp); /* * See fclose(3). Further access to out_fp after both success * and error, even through another bt_close_memstream(), results * in undefined behavior. Nullify out_fp to ensure we don't * fclose it twice on error. */ out_fp = NULL; if (ret < 0) { BT_LOGE("Cannot close memory stream: %s: mdec-addr=%p", strerror(errno), mdec); goto error; } goto end; error: ret = -1; if (out_fp) { if (bt_close_memstream(buf, &size, out_fp)) { BT_LOGE("Cannot close memory stream: %s: mdec-addr=%p", strerror(errno), mdec); } } if (*buf) { free(*buf); *buf = NULL; } end: return ret; }
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); }
static int decode_packet(struct ctf_metadata_decoder *mdec, FILE *in_fp, FILE *out_fp, int byte_order) { struct packet_header header; size_t readlen, writelen, toread; uint8_t buf[512 + 1]; /* + 1 for debug-mode \0 */ int ret = 0; const long offset = ftell(in_fp); if (offset < 0) { BT_LOGE_ERRNO("Failed to get current metadata file position", "."); goto error; } BT_LOGV("Decoding metadata packet: mdec-addr=%p, offset=%ld", mdec, offset); readlen = fread(&header, sizeof(header), 1, in_fp); if (feof(in_fp) != 0) { BT_LOGV("Reached end of file: offset=%ld", ftell(in_fp)); goto end; } if (readlen < 1) { BT_LOGV("Cannot decode metadata packet: offset=%ld", offset); goto error; } if (byte_order != BYTE_ORDER) { header.magic = GUINT32_SWAP_LE_BE(header.magic); header.checksum = GUINT32_SWAP_LE_BE(header.checksum); header.content_size = GUINT32_SWAP_LE_BE(header.content_size); header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size); } if (header.compression_scheme) { BT_LOGE("Metadata packet compression is not supported as of this version: " "compression-scheme=%u, offset=%ld", (unsigned int) header.compression_scheme, offset); goto error; } if (header.encryption_scheme) { BT_LOGE("Metadata packet encryption is not supported as of this version: " "encryption-scheme=%u, offset=%ld", (unsigned int) header.encryption_scheme, offset); goto error; } if (header.checksum || header.checksum_scheme) { BT_LOGE("Metadata packet checksum verification is not supported as of this version: " "checksum-scheme=%u, checksum=%x, offset=%ld", (unsigned int) header.checksum_scheme, header.checksum, offset); goto error; } if (!is_version_valid(header.major, header.minor)) { BT_LOGE("Invalid metadata packet version: " "version=%u.%u, offset=%ld", header.major, header.minor, offset); goto error; } /* Set expected trace UUID if not set; otherwise validate it */ if (mdec) { if (!mdec->is_uuid_set) { memcpy(mdec->uuid, header.uuid, sizeof(header.uuid)); mdec->is_uuid_set = true; } else if (bt_uuid_compare(header.uuid, mdec->uuid)) { BT_LOGE("Metadata UUID mismatch between packets of the same stream: " "packet-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", " "expected-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", " "offset=%ld", (unsigned int) header.uuid[0], (unsigned int) header.uuid[1], (unsigned int) header.uuid[2], (unsigned int) header.uuid[3], (unsigned int) header.uuid[4], (unsigned int) header.uuid[5], (unsigned int) header.uuid[6], (unsigned int) header.uuid[7], (unsigned int) header.uuid[8], (unsigned int) header.uuid[9], (unsigned int) header.uuid[10], (unsigned int) header.uuid[11], (unsigned int) header.uuid[12], (unsigned int) header.uuid[13], (unsigned int) header.uuid[14], (unsigned int) header.uuid[15], (unsigned int) mdec->uuid[0], (unsigned int) mdec->uuid[1], (unsigned int) mdec->uuid[2], (unsigned int) mdec->uuid[3], (unsigned int) mdec->uuid[4], (unsigned int) mdec->uuid[5], (unsigned int) mdec->uuid[6], (unsigned int) mdec->uuid[7], (unsigned int) mdec->uuid[8], (unsigned int) mdec->uuid[9], (unsigned int) mdec->uuid[10], (unsigned int) mdec->uuid[11], (unsigned int) mdec->uuid[12], (unsigned int) mdec->uuid[13], (unsigned int) mdec->uuid[14], (unsigned int) mdec->uuid[15], offset); goto error; } } if ((header.content_size / CHAR_BIT) < sizeof(header)) { BT_LOGE("Bad metadata packet content size: content-size=%u, " "offset=%ld", header.content_size, offset); goto error; } toread = header.content_size / CHAR_BIT - sizeof(header); for (;;) { size_t loop_read; loop_read = MIN(sizeof(buf) - 1, toread); readlen = fread(buf, sizeof(uint8_t), loop_read, in_fp); if (ferror(in_fp)) { BT_LOGE("Cannot read metadata packet buffer: " "offset=%ld, read-size=%zu", ftell(in_fp), loop_read); goto error; } if (readlen > loop_read) { BT_LOGE("fread returned more byte than expected: " "read-size-asked=%zu, read-size-returned=%zu", loop_read, readlen); goto error; } writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp); if (writelen < readlen || ferror(out_fp)) { BT_LOGE("Cannot write decoded metadata text to buffer: " "read-offset=%ld, write-size=%zu", ftell(in_fp), readlen); goto error; } toread -= readlen; if (toread == 0) { int fseek_ret; /* Read leftover padding */ toread = (header.packet_size - header.content_size) / CHAR_BIT; fseek_ret = fseek(in_fp, toread, SEEK_CUR); if (fseek_ret < 0) { BT_LOGW_STR("Missing padding at the end of the metadata stream."); } break; } } goto end; error: ret = -1; end: return ret; }